/// <summary>
        /// draw row and table items inside body. 
        /// table items are treated as tables 
        /// </summary>
        public void DrawBody(Hashtable data, IPDFDraw drawer)
        {
            if (bodyItems == null)
                return;

            XmlAttributeCollection font = pdfTemplate.DefaultFontAttrs;
            if (bodyNode.FirstChild.Name == "font")
            {
                font = bodyNode.FirstChild.Attributes;
            }

            foreach (XmlNode itemNode in bodyItems)
            {
                if (!IsNodeVisible(itemNode, data))
                    continue;

                if (itemNode.Name == "row")
                {
                    RowGroup rowGroup = new RowGroup
                    {
                        Y = Helper.GetFloatAttributeValue("y", bodyNode.Attributes, -1)
                    };
                    rowGroup.AddRow(pdfTemplate._buildRow(itemNode, font));
                    pdfTemplate.DrawRowGroup(rowGroup, data, DocumentGroup.Body);
                }
                else if (itemNode.Name == "table")
                {
                    var tableGenerator = new TableGenerator(pdfTemplate, itemNode);
                    if (itemNode.Attributes == null)
                        continue;
                    var keyAttribute = itemNode.Attributes["var"];
                    if (keyAttribute == null || !data.ContainsKey(keyAttribute.Value))
                        continue;
                    var tableParameters = data[keyAttribute.Value];
                    if (!(tableParameters is TableData))
                        throw new Exception("table parameter must be of type TableData");

                    tableGenerator.DrawTable((TableData) (tableParameters), drawer);
                }
            }
        }
        /// <summary>
        /// draw row and table items inside body.
        /// table items are treated as tables
        /// </summary>
        public void DrawBody(Hashtable data, IPDFDraw drawer)
        {
            if (bodyItems == null)
            {
                return;
            }

            XmlAttributeCollection font = pdfTemplate.DefaultFontAttrs;

            if (bodyNode.FirstChild.Name == "font")
            {
                font = bodyNode.FirstChild.Attributes;
            }

            foreach (XmlNode itemNode in bodyItems)
            {
                if (!IsNodeVisible(itemNode, data))
                {
                    continue;
                }

                if (itemNode.Name == "row")
                {
                    RowGroup rowGroup = new RowGroup
                    {
                        Y = XmlHelper.GetFloatAttributeValue("y", bodyNode.Attributes, -1)
                    };
                    // add new page if the attribute "newPage" == "true"
                    var newPageAttribute = itemNode.Attributes?["newPage"];
                    if (newPageAttribute != null && newPageAttribute.Value == "true")
                    {
                        var orientationAttribute = itemNode.Attributes?["orientation"];
                        if (orientationAttribute == null)
                        {
                            pdfTemplate.NextPage();
                        }
                        else if (orientationAttribute.Value.ToUpper() == "LANDSCAPE")
                        {
                            pdfTemplate.NextPage(Orientation.Landscape);
                        }
                        else
                        {
                            pdfTemplate.NextPage(Orientation.Portrait);
                        }

                        pdfTemplate.DrawHeader();
                    }
                    rowGroup.AddRow(pdfTemplate._buildRow(itemNode, font));
                    pdfTemplate.DrawRowGroup(rowGroup, data, DocumentGroup.Body);
                }
                else if (itemNode.Name == "table")
                {
                    var tableGenerator = new TableGenerator(pdfTemplate, itemNode);
                    if (itemNode.Attributes == null)
                    {
                        continue;
                    }
                    var keyAttribute = itemNode.Attributes["var"];
                    if (keyAttribute == null || !data.ContainsKey(keyAttribute.Value))
                    {
                        continue;
                    }
                    // add new page if the attribute "newPage" == "true"
                    var newPageAttribute = itemNode.Attributes?["newPage"];
                    if (newPageAttribute != null && newPageAttribute.Value == "true")
                    {
                        pdfTemplate.NextPage();
                        pdfTemplate.DrawHeader();
                    }
                    var tableParameters = data[keyAttribute.Value];
                    if (!(tableParameters is TableData))
                    {
                        throw new Exception("table parameter must be of type TableData");
                    }

                    tableGenerator.DrawTable((TableData)tableParameters, drawer);
                }
            }
        }
        /// <summary>
        /// override base _buildPageDef but still call it first
        /// implement table here
        /// </summary>
        protected override void _buildPageDef()
        {
            // call base to build footer, loop, body, footer from xml
            base._buildPageDef();
            //Console.WriteLine("call _buildPageDef in PDFTemplateItextSharp");

            // here, we build the table from xml
            XmlElement elmRoot = XMLTemplate.DocumentElement;
            XmlNode tableNode = elmRoot.SelectSingleNode("//table");

            if (tableNode != null)
                principalTableGenerator = new TableGenerator(this, tableNode);

            XmlNode bodyNode = elmRoot.SelectSingleNode("//body");
            if (tableNode != null)
                bodyGenerator = new BodyGenerator(this, bodyNode);
        }