2016-04-28 12 views
2

この質問はXmlReaderに固有であり、XDocumentまたはXmlReaderを使用するかどうかには関係ありません。XmlReaderが要素をスキップするのはなぜですか?

私のようにXMLフラグメントを持っている:

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>"; 
} 

私としても拡張メソッドを持っています。

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; 
     } 
    } 
} 

私はその後、実行して2つのbookの要素を取得しよう:

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); 
} 

しかし、私は最初の要素であるdebug私が最初の要素を取得するとすぐに、リーダーはbook要素のtitleにジャンプします。

溶液はすべてのヘルプははるかに高く評価されてHERE

からインスピレーションを得ています。

+0

。あなたのメソッドは、私のマシン上に2つの要素を持つシーケンスを生成します。 'this.GetXmlFragment()'は、あなたが提供したXMLを生成すると確信していますか? –

+0

奇妙な質問を更新しました – babayi

+0

https://dotnetfiddle.net/ssrAG1を参照してください。何とかあなたのデバッグが干渉しているのでしょうか? –

答えて

2

介在する空白がない場合、XNode.ReadFrom()を呼び出すと、XMLリーダーが次の要素の右に置かれてしまうという問題があります。 whileの条件は、チェックする前にこの要素をただちに消費します。修正は直後にXmlReader.Read()を呼び出さないために、しかし(読み取りが暗黙的に行われているとして)ノードのチェックを継続することです:

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

(それははっきりしていない場合は、ループ内ifに変更されました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

ブックタグはすぐにお互いに従っているため、コードが他のすべての書籍タグをスキップされます。 readメソッドは、リーダーを次のbookタグに置き、readメソッドが移動して、要素をスキップする2番目のbookタグを読み取ります。私が開発したコードを試してみてください。他の人のように

 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

が言っている(それらの間に空白が存在しない場合)、XNode.ReadFromは次の本オープンタグにあなたの読者を進めているその後reader.Readは、そのタグの内部テキストに進みます。

は、詳細についてはこちらを参照してください:あなたの拡張メソッドのための

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

修正:再現することができません

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(); 
     } 
    } 
} 
関連する問題