使用XmlReader获取XML文档的所有元素(流)

时间:2014-06-26 23:08:10

标签: c# xml linq

我正在尝试解析从流中读入的xml文档,查找元素并将它们作为XElements返回。我希望能够创建一个更通用的读者来获取文档中的每个元素,以便我可以在调用函数中使用linq查询来过滤我想要的内容。因此,假设我想获得"标题"," book"和" bookdata"来自以下xml的元素:

<parent>
  <header>
    <data>text</data>
  </header>
  <books>
    <book>
      <bookdata>
        <title>book 1 title</title>
        <author>author 1</author>
      </bookdata>
      <otherinfo>info1</otherinfo>
    </book>
    <book>
      <bookdata>
        <title>book 2 title</title>
        <author>author 2</author>
      </bookdata>
      <otherinfo>info2</otherinfo>
    </book>
  </books>
</parent>

我已根据Leonard Lobel

中的代码实现了以下内容
private static IEnumerable<XElement> GetElements(Stream data)
{
    using (XmlReader reader = CreateSecureXmlReader(data))
    {
        reader.MoveToContent();
        while (reader.Read())
        {
            if (reader.NodeType == XmlNodeType.Element)
            {
                var e = XElement.ReadFrom(reader) as XElement;
                yield return e;
            }
        }
    }
}

它被称为如下:

var elements = from el in GetElements(stream)
               where el.Name == "header" ||
               el.Name == "book" ||
               el.Name == "bookdata"
               select el;

foreach (var xElement in elements)
{
     Console.WriteLine(xElement.Name);
}

问题在于,一旦它将元素作为XElement读取,它就会向前跳过并且无法在此元素中查找匹配项。即我得到输出:

header

因为读取并返回了标头(由于某种原因跳过了父级)。但随后它会读取&#34; books&#34;,将其作为XElement返回,此时我假设XmlReader接下来会查看&#34; books&#34;这只是一些结束元素和文档的结尾。它没有机会向内心寻找&#34; book&#34;和#34; bookdata&#34;。

在伦纳德·洛贝尔的例子中,他传递了他正在寻找的元素名称,但即使我传递了我想要的元素的名称,我仍然遇到了问题,其中&#34;预订&# 34;消费了它并没有在里面看到#book; bookdata&#34;。

如果有人知道如何查看所有元素并将它们作为XElements返回,或者有更好的解决方案来查找和返回元素及其子元素,那么我们将非常感激。

1 个答案:

答案 0 :(得分:0)

实施leonard lobels方法(注意参数):

    private static IEnumerable<XElement> StreamElements(string fileName, params string[] elementsName)         
    {
          using (var rdr = XmlReader.Create(fileName))
          {
              rdr.MoveToContent();
              while (rdr.Read())
              {
                  if ((rdr.NodeType == XmlNodeType.Element) && (elementsName.Contains(rdr.Name)))
                  {
                      var e = XElement.ReadFrom(rdr) as XElement;
                      yield return e;
                  }
              }
              rdr.Close();
          }
     }

在您的代码中(这是一个示例,您可以按照自己的方式实现):

List<XElement> myElements = new List<XElement>();
foreach (var item in StreamElements("YourXMLfile.xml", "book", "bookdata", "header"))
{
     myElements.Add(item);
}