使用XmlReader获取最后一个子元素

时间:2017-10-16 15:46:35

标签: c# xml

说我有这个XML:

 <fields>
        <field fieldid="fdtElem3Group">
          <value actionid="1" actiontype="review">123456789</value>
          <value actionid="2" actiontype="review">123456789</value>
          <value actionid="3" actiontype="review">123456789</value>
          <value actionid="4" actiontype="review">123456789</value>
          <value actionid="5" actiontype="review">123456789</value>
        </field>
        <field fieldid="fdtElem7Group">
          <value actionid="1" actiontype="review">29/10/75</value>
          <value actionid="2" actiontype="review">29/10/74</value>
          <value actionid="3" actiontype="review">29/10/74</value>
          <value actionid="4" actiontype="review">29/10/76</value>
          <value actionid="5" actiontype="review">29/10/74</value>
        </field>
      </fields>

我正在尝试使用XmlReader获取每个相应“字段”元素的最后一个'value'元素的值。我该怎么办?这不起作用:

while (xmlReader.Read())
{
    if ((xmlReader.NodeType == System.Xml.XmlNodeType.Element) && (xmlReader.Name == "field"))
    {
        xmlReader.ReadToDescendant("value");
        while (xmlReader.ReadToNextSibling("value"))
        {
            //just iterate over until it reaches the end
        }
        xmlReader.Read();
        Console.WriteLine(xmlReader.Value);
    }
}

3 个答案:

答案 0 :(得分:1)

很抱歉,现在阅读您正在寻找xmReader解决方案。但是使用XDocument和Linq,您可以执行以下操作:

string xml = @"<fields>
        <field fieldid=""fdtElem3Group"">
          <value actionid=""1"" actiontype=""review"">123456789</value>
          <value actionid=""2"" actiontype=""review"">123456789</value>
          <value actionid=""3"" actiontype=""review"">123456789</value>
          <value actionid=""4"" actiontype=""review"">123456789</value>
          <value actionid=""5"" actiontype=""review"">123456789</value>
        </field>
        <field fieldid=""fdtElem7Group"">
          <value actionid=""1"" actiontype=""review"">29/10/75</value>
          <value actionid=""2"" actiontype=""review"">29/10/74</value>
          <value actionid=""3"" actiontype=""review"">29/10/74</value>
          <value actionid=""4"" actiontype=""review"">29/10/76</value>
          <value actionid=""5"" actiontype=""review"">29/10/74</value>
        </field>
      </fields>";



var xmlDoc = XDocument.Parse(xml).Root;
var lastElements = xmlDoc.Descendants("field").Select(x => x.LastNode);

答案 1 :(得分:1)

希望这有帮助!

static void Main(string[] args)
        {
            string xml = @"<fields><field fieldid='fdtElem3Group'><value actionid='1' actiontype='review'>123456789</value><value actionid='2' actiontype='review'>123456789</value><value actionid='3' actiontype='review'>123456789</value><value actionid='4' actiontype='review'>123456789</value><value actionid='5' actiontype='review'>123456789</value></field><field fieldid='fdtElem7Group'><value actionid='1' actiontype='review'>29/10/75</value>          <value actionid='2' actiontype='review'>29/10/74</value><value actionid='3' actiontype='review'>29/10/74</value><value actionid='4' actiontype='review'>29/10/76</value><value actionid='5' actiontype='review'>29/10/74</value></field></fields>";
            XmlDocument xmlDocument = new XmlDocument();
            xmlDocument.LoadXml(xml);
            foreach (XmlNode item in xmlDocument.DocumentElement.ChildNodes)
            {
                Console.WriteLine(item.LastChild.InnerXml);
            }            
            Console.ReadKey();
        }

答案 2 :(得分:1)

如果您不想将整个XML加载到XDocument(因为它非常大),您可以采用混合方法,使用XmlReader来迭代XML文件中的<field><value>元素,将每个<value>元素加载到XElement,然后选择每个父<field>的最后一个元素。无论XML文件增长多大,这都会使内存占用量保持很小且不变。

首先介绍以下两种扩展方法:

public static class XmlReaderExtensions
{
    public static IEnumerable<IEnumerable<XElement>> ReadNestedElements(this XmlReader xmlReader, string outerName, string innerName)
    {
        while (!xmlReader.EOF)
        {
            if (xmlReader.NodeType == System.Xml.XmlNodeType.Element && xmlReader.Name == outerName)
            {
                using (var subReader = xmlReader.ReadSubtree())
                {
                    yield return subReader.ReadElements(innerName);
                }
            }
            xmlReader.Read();
        }
    }

    public static IEnumerable<XElement> ReadElements(this XmlReader xmlReader, string name)
    {
        while (!xmlReader.EOF)
        {
            if (xmlReader.NodeType == System.Xml.XmlNodeType.Element && xmlReader.Name == name)
            {
                var element = (XElement)XNode.ReadFrom(xmlReader);
                yield return element;
            }
            else
            {
                xmlReader.Read();
            }
        }
    }
}

然后你的算法得到最后的价值&#39;每个领域的元素&#39;元素变得非常简单:

public static List<string> LastFieldValues(XmlReader reader)
{
    var query = reader.ReadNestedElements("field", "value")
        .Select(l => l.LastOrDefault())
        .Where(v => v != null)
        .Select(v => (string)v);

    return query.ToList();
}

注意:

  • XmlReaderExtensions.ReadNestedElements()返回属于<value>元素的<field>个元素的可枚举数。然后使用Enumerable.LastOrDefault()选择属于每个<value>的最后一个<field>

  • 每当直接使用XmlReader时,请务必使用和不使用缩进来测试XML,原因如herehere所述。

  • XmlReader.ReadSubtree()使XmlReader位于位于正在读取的元素的EndElement节点上,而XNode.ReadFrom()会将读取器放置在位置紧跟正在读取的元素的EndElement节点之后。只是一个烦人的不一致,需要注意。

另一方面,如果您愿意将整个XML作为XDocument加载到内存中,可以使用XPathSelectElements()非常简单地完成此操作:

// Parse the XML into an XDocument.
// You can use use XDocument.Load(fileName) to load from a file
var doc = XDocument.Parse(xmlString); 
var xpathLastValues = doc
    .XPathSelectElements(@"//fields/field/value[last()]")
    .Select(e => e.Value)
    .ToList();

示例fiddle