views:

226

answers:

1

Hello.

Im trying to build a simple XML to Controls parser in my CF application. In the code below the string im trying to parse looks like this:

"<Panel><Label>Text1</Label><Label>Text2</Label></Panel>"

The result i want with this code would be a Panel with two labels. But the problem is when the first Label is parsed the subreader.Read() returns false in the ParsePanelElementh method, and so it falls out of while statement. Since im new into XMLReader i must be missing something very simple. Any help would be apreciated !

peace.

static class XMLParser
{
    public static Control Parse(string aXmlString)
    {
        XmlReader reader = XmlReader.Create(new StringReader(aXmlString));
        return ParseXML(reader);
    }

    public static Control ParseXML(XmlReader reader)
    {
        using (reader)
        {
            while (reader.Read())
            {
                if (reader.NodeType == XmlNodeType.Element)
                {
                    if (reader.LocalName == "Panel")
                    {
                        return ParsePanelElement(reader);
                    }

                    if (reader.LocalName == "Label")
                    {
                        return ParseLabelElement(reader);
                    }
                }
            }
        }
        return null;
    }

    private static Control ParsePanelElement(XmlReader reader)
    {
        var myPanel = new Panel();
        XmlReader subReader = reader.ReadSubtree();
        while (subReader.Read())
        {
            Control subControl = ParseXML(subReader);
            if (subControl != null)
            {
                myPanel.Controls.Add(subControl);
            };
        }
        return myPanel;
    }

    private static Control ParseLabelElement(XmlReader reader)
    {
        reader.Read();
        var myString = reader.Value as string;
        var myLabel = new Label();
        myLabel.Text = myString;
        return myLabel;
    }
}
+2  A: 

The problem is that the reader reads twice, once in ParsePanelElement and once in ParseXML. This way you parse the panel, skip the first label and eventually add the second label.

[EDIT May 3rd 2010]

This code works under Visual Studio 9. (I have moved the using clause)

   static class Program
   {
      /// <summary>
      /// The main entry point for the application.
      /// </summary>
      [STAThread]
      static void Main()
      {
         Control Test = XMLParser.Parse("<Panel><Label>Text1</Label><Label>Text2</Label></Panel>");
         for (Int32 i = 0; i < Test.Controls.Count; i++)
         {
            System.Diagnostics.Debug.WriteLine("Control " + i + ": " + Test.Controls[i].GetType().FullName + " [TEXT = " + Test.Controls[i].Text + "]");
         }
      }

      static class XMLParser
      {
         public static Control Parse(string aXmlString)
         {
            Control result = null;
            using (StringReader strReader = new StringReader(aXmlString))
            {
               using (XmlReader reader = XmlReader.Create(strReader))
               {
                  result = ParseXML(reader);
               }
            }
            return result;
         }

         public static Control ParseXML(XmlReader reader)
         {
            while (reader.Read())
            {
               if (reader.NodeType == XmlNodeType.Element)
               {
                  if (reader.LocalName == "Panel")
                  {
                     return ParsePanelElement(reader);
                  }

                  if (reader.LocalName == "Label")
                  {
                     return ParseLabelElement(reader);
                  }
               }
            }
            return null;
         }

         private static Control ParsePanelElement(XmlReader reader)
         {
            var myPanel = new Panel();
            using (XmlReader subReader = reader.ReadSubtree())
            {
               while (subReader.Read())
               {
                  Control subControl = ParseXML(subReader);
                  if (subControl != null)
                  {
                     myPanel.Controls.Add(subControl);
                  };
               }
            }
            return myPanel;
         }

         private static Control ParseLabelElement(XmlReader reader)
         {
            reader.Read();
            var myString = reader.Value as string;
            var myLabel = new Label();
            myLabel.Text = myString;
            return myLabel;
         }
      }
   }
Roy
the result im gettin is a panel with only the first label. In ParsePanelElement i read subReader and not the original reader again. Since its a simple example, could you fix the code for me so i understand what im doing wrong?
no9
i thought i found the problem in ParseLabelElement.I substituted:"reader.Read(); var myString = reader.Value as string;" to "var myString = reader.ReadElementContentAsString();".But the problem remains, as when this is called the reader position changes to next node (in my case second label). Is there a way to read the node value and stay on the same position?
no9
Is the reader.Read() necessary at that point? I can't check right now since i don't have Visual Studio here.. It seems that in `ParsePanelElement` you read the first node, when `ParsePanelElement` calls `ParseXml` you read another node, and when `parseXml` calls `ParseLabelElement` you read another node. Also, does that using statement work? i thought using statements only work when declaring a new assigned object in it? If it does work, this could be the cause of your problem too. The using statement closes the subreader so the while loops exit.
Roy
The problem is when ParsePanelElement calls ParseXML, and when it goes into the ParseLabelElement all is OK. At the point, just before it returns back to ParsePanelElement (in ParseXML method) the reader (in my case the reader in ParseXML is actualy subreader fetched from ParseElement method) is in the right position. But when it returns to the ParsePanelElement the subreader is in different position, so thats why it breaks the while loop in the ParsePanelElement. The using statement doesnt seem to cause any problems as when i removed it the problem is still there.
no9
Also i fixed the problem in my pre-previous post (in ParseLabelElement) by using "reader.ReadString();" method, that fetches the current node value and keeps the reader in the same position. Frustrating ! :S
no9
thanx for your anwser ! I already have this working using xml(linq). But i will also use this aproach.
no9