3

Hi all I have attempted to write a simple xml reader but have found that it unintentionally skips every other element in the xml file.

Im guessing I am telling it to move onto the next element twice but I am unsure how whats happening or what the solution is.

any help will be greatly appreciated :)

here is a sample of the code and a sample of the xml file

public LevelLoader(string theLevelFile ,ContentManager theContent)
    {
        XmlTextReader reader = new XmlTextReader(theLevelFile);
        while (reader.Read())
        {               
            if (reader.NodeType == XmlNodeType.Element)
            {
                switch (reader.Name)
                {
                    case "tilerow":
                    {                            
                        currentRow = currentRow + 1;
                        Console.WriteLine("row found");
                        currentCol = 0;
                        break;
                    }

                    case "tilecol":
                    {
                        Console.WriteLine("col found");                                                                                                                         
                        currentTexture = reader.ReadElementContentAsFloat();                          
                        currentCol = currentCol + 1;
                        break;
                    }
                }
            }
        }
    }

sample xml

<tilerow>
<tilecol>1</tilecol><tilecol>2</tilecol><tilecol>3</tilecol><tilecol>4</tilecol><tilecol>5</tilecol><tilecol>6</tilecol><tilecol>7</tilecol><tilecol>8</tilecol><tilecol>9</tilecol><tilecol>10</tilecol>
</tilerow>
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
Iain
  • 35
  • 1
  • 4

3 Answers3

3

The Read() method will first return the Column element, then the Column "Text" then the EndElement. When you use ReadElementContentAsFloat, it reads the current content, then positions the next Read() to the next "Text" section. Since your loop is skipping the Text and the EndElement, it misses 2, 4, ...

Try this instead...

case "tilecol": 
{ 
Console.WriteLine("col found");
reader.Read();
float.TryParse(reader.Value, out currentTexture);
currentCol = currentCol + 1;
break;
} 
Les
  • 10,335
  • 4
  • 40
  • 60
2

See this page: http://msdn.microsoft.com/en-us/library/ms223980.aspx

In short, ReadElementContentAsFloat move the reader to the next element and so is the "main" reader.Read() of the loop.

Here is new loop taking into account this new behavior:

while (!reader.EOF)
{
    bool needToRead = true;
    if (reader.NodeType == XmlNodeType.Element)
    {
        switch (reader.Name)
        {
            case "tilerow":
                currentRow = currentRow + 1;
                Console.WriteLine("row found");
                currentCol = 0;
                break;

            case "tilecol":
                Console.WriteLine("col found");                                                                                                                         
                currentTexture = reader.ReadElementContentAsFloat();                          
                currentCol = currentCol + 1;
                needToRead = false;
                break;
        }
    }
    if (needToRead)
        reader.Read();
}
Shadow The GPT Wizard
  • 66,030
  • 26
  • 140
  • 208
0

according to @Shadow Wizard's answer when writing your own ReadXml method in a serializable class TileRow

public void ReadXml(XmlReader reader)
{
    reader.Read();
    do
    {
        if (!XmlNodeType.Element.Equals(reader.NodeType))
        {
            if (!XmlNodeType.EndElement.Equals(reader.NodeType))
            {
                log.error(reader.NodeType + " is an unknown NodeType for " + this.GetType());
            }
            // return while further reading would move the reader position to another / outer element and will lead to skipped elements in parser
            return;
        }
        switch (reader.Name)
        {
            case "tilecol":
                col = reader.ReadElementContentAsFloat();
                break;

             default:
                log.error(reader.Name + " is not a valid XMLElement for " + this.GetType());
                reader.Read();
                break;
        }
    }
    while (!reader.EOF);
 }

for manual writer:

public void WriteXml(XmlWriter writer)
{
    writer.WriteElementString("tilecol", col.ToString());
}

so you can use TileRow as an XMLElement

[XmlElement]
public TileRow tileRow { get; set; }
childno͡.de
  • 4,679
  • 4
  • 31
  • 57