【问题标题】:Get last child element using XmlReader使用 XmlReader 获取最后一个子元素
【发布时间】:2017-10-16 15:46:34
【问题描述】:

假设我有这个 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 获取每个相应“字段”元素的最后一个“值”元素的值。请问我该怎么做?这不起作用:

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

【问题讨论】:

  • 为什么不使用XDocument 和一些XPath?

标签: c# xml


【解决方案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);

【讨论】:

  • Linq to Xml 恕我直言,它比 .Net 中当前可用的任何其他功能都强大得多。
【解决方案2】:

希望这会有所帮助!

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

【讨论】:

    【解决方案3】:

    如果您不想将整个 XML 加载到 XDocument 中(例如,它非常大),您可以采用混合方法,使用 XmlReader 遍历 &lt;field&gt;&lt;value&gt; XML 文件中的元素,将每个&lt;value&gt; 元素加载到XElement 中,然后选择每个父&lt;field&gt; 的最后一个元素。无论 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();
                }
            }
        }
    }
    

    那么您获取每个“字段”元素的最后一个“值”元素的算法变得非常简单:

    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() 返回属于&lt;field&gt; 元素的&lt;value&gt; 元素的可枚举。然后使用Enumerable.LastOrDefault() 选择属于每个&lt;field&gt; 的最后一个&lt;value&gt;

    • 当直接使用 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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-03-08
      • 1970-01-01
      • 2014-05-31
      • 1970-01-01
      • 1970-01-01
      • 2021-06-19
      • 1970-01-01
      • 2010-11-30
      相关资源
      最近更新 更多