2016-04-28 14 views
2

Bitte beachten Sie, diese Frage ist spezifisch für XmlReader und nicht, ob XDocument oder XmlReader zu verwenden.Warum überspringt der XmlReader Elemente?

Ich habe ein XML Fragment als:

private string GetXmlFragment() 
{ 
    return @"<bookstore> 
      <book genre='novel' ISBN='10-861003-324'> 
      <title>The Handmaid's Tale</title> 
      <price>19.95</price> 
      </book> 
      <book genre='novel' ISBN='1-861001-57-5'> 
      <title>Pride And Prejudice</title> 
      <price>24.95</price> 
      </book> 
     </bookstore>"; 
} 

ich auch eine Erweiterungsmethode haben, wie:

public static IEnumerable<XElement> GetElement(this XmlReader reader, string elementName) 
{ 
    reader.MoveToElement(); 

    while (reader.Read()) 
    { 
     if (reader.NodeType == XmlNodeType.Element 
      && reader.Name.Equals(elementName, StringComparison.InvariantCulture)) 
     { 
      yield return XNode.ReadFrom(reader) as XElement; 
     } 
    } 
} 

ich dann versuchen, die beiden book Elemente zu erhalten, indem Sie:

var xmlReaderSettings = new XmlReaderSettings 
{ 
    CheckCharacters = false, 
    ConformanceLevel = ConformanceLevel.Fragment, 
    IgnoreComments = true, 
    IgnoreWhitespace = true, 
    IgnoreProcessingInstructions = true 
}; 

using (var stringReader = new StringReader(this.GetXmlFragment())) 
using (var xmlReader = XmlReader.Create(stringReader, xmlReaderSettings)) 
{ 
    xmlReader.GetElement("book").Count().ShouldBe(2); 
} 

Allerdings bekomme ich nur das erste Element, debuggen ging zeigt, dass sobald ich das erste Element bekomme, der Leser zum title des zweiten book Elements springt.

Die Lösung von HERE

Jede Hilfe ist inspiriert wird sehr geschätzt.

+0

konnte nicht reproduzieren. Ihre Methode erzeugt eine Sequenz mit zwei Elementen auf meinem Computer. Sind Sie sicher, dass 'this.GetXmlFragment()' den von Ihnen bereitgestellten XML-Code erzeugt? –

+0

Seltsam, Ich habe die Frage aktualisiert, um die Methode – babayi

+0

zu enthalten Siehe https://dotnetfiddle.net/ssrAG1. Stört das Debugging irgendwie, vielleicht? –

Antwort

2

Das Problem ist, dass der Aufruf von XNode.ReadFrom() den XML-Reader direkt an das nächste Element positioniert, wenn kein Leerzeichen dazwischen liegt. Die while Bedingung verbraucht dann sofort dieses Element, bevor wir es überprüfen können. Die Lösung ist nicht XmlReader.Read() zu rufen unmittelbar danach, aber für Knoten überprüft, um fortzufahren (wie die Lese implizit geschehen ist):

while (reader.Read()) { 
    while (reader.NodeType == XmlNodeType.Element 
      && reader.Name.Equals(elementName, StringComparison.InvariantCulture)) { 
     yield return XNode.ReadFrom(reader) as XElement; 
    } 
} 

(Falls nicht klar, es ist, hat die if in der Schleife ein geändert while.)

1
public static IEnumerable<XElement> GetElement(this XmlReader reader, string elementName) 
{ 
    while (!reader.EOF) 
     if (reader.NodeType == XmlNodeType.Element && reader.Name == "book") 
      yield return XNode.ReadFrom(reader) as XElement; 
     else 
      reader.Read(); 
} 
0

Der Code jeden anderen Buch-Tages wird das Überspringen weil das Buch Tags unmittelbar aufeinander folgen. Die Lese-Methode belässt den Leser beim nächsten book-Tag und dann bewegt sich die Lese-Methode, bevor das zweite book-Tag das Element überspringt. Versuchen Sie den Code, den ich entwickelt habe und immer funktioniert.

 public static IEnumerable<XElement> GetElement(XmlReader reader, string elementName) 
     { 
      List<XElement> books = new List<XElement>(); 


      while (!reader.EOF) 
      { 
       if(reader.Name != "book") 
       { 
        reader.ReadToFollowing("book"); 
       } 
       if(!reader.EOF) 
       { 
        books.Add((XElement)XElement.ReadFrom(reader)); 
       } 
      } 
      return books; 
     } 
0

Wie andere gesagt haben, XNode.ReadFrom voran Ihre Leser auf das nächste Buch offen Tag (wenn es keine Leerzeichen zwischen ihnen) dann reader.Read mit dem inneren Text dieser Tag vorrücken wird.

Sehen Sie hier für weitere Informationen:

https://stackoverflow.com/a/26788230/3850405

Fix für Ihre Erweiterungsmethode:

public static IEnumerable<XElement> GetElement(this XmlReader reader, string elementName) 
{ 
    reader.MoveToElement(); 

    reader.Read(); 
    while (!reader.EOF) 
    { 
     if (reader.NodeType == XmlNodeType.Element 
      && reader.Name.Equals(elementName, StringComparison.InvariantCulture)) 
     { 
      yield return XNode.ReadFrom(reader) as XElement; 
     } 
     else 
     { 
      reader.Read(); 
     } 
    } 
} 
Verwandte Themen