【问题标题】:Use XMLReader to access child nodes with duplicate names使用 XMLReader 访问具有重复名称的子节点
【发布时间】:2011-01-19 23:45:50
【问题描述】:

使用下面的 XML 片段,我如何使用 XMLReader 访问节点 <salesTaxAmt> 的子节点 <amt>?如果我遍历节点以查找节点名称“amt”,则返回最后一个节点数量 <sourceCurrAmt>,即 0.00。

<transactionUnit>
<transactionDetails>
<transactionId>11883382</transactionId>
<currencyAmount>
  <amt>30.00</amt>
  <currCode>USD</currCode>
</currencyAmount>
<gstAmount>
  <amt>60.00</amt>
  <currCode>USD</currCode>
</gstAmount>
<pstNqstAmt>
  <amt>0.00</amt>
  <currCode>USD</currCode>
</pstNqstAmt>
<salesTaxAmt>
  <amt>1.00</amt>
  <currCode>USD</currCode>
</salesTaxAmt>
<sourceCurrAmt>
  <amt>0.00</amt>
</sourceCurrAmt>
</transactionDetails>
</transactionUnit>

下面的代码是不是最好的方法?

测试代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;

namespace TestConsole
{
    public class ParseXML
    {
        static void Main(string[] args)
        {
            try
            {
                FileStream file;
                XmlReader baseReader;
                XmlTextReader reader;
                XmlReaderSettings readerSettings;

                file = new FileStream(@"C:\Data.xml", FileMode.Open, FileAccess.Read);
                file.Seek(0, SeekOrigin.Begin);

                reader = new XmlTextReader(file, XmlNodeType.Element, null);
                reader.Normalization = false;

                readerSettings = new XmlReaderSettings();
                readerSettings.ConformanceLevel = ConformanceLevel.Fragment;
                readerSettings.IgnoreWhitespace = false;
                readerSettings.IgnoreComments = true;
                readerSettings.CheckCharacters = false;

                baseReader = XmlReader.Create(reader, readerSettings);
                int x = 0;
                while (baseReader.Read())
                {
                    if (baseReader.Name.Equals("transactionUnit") && (baseReader.NodeType == XmlNodeType.Element))
                    {
                        string amt = null;
                        XmlReader inner = reader.ReadSubtree();
                        while (inner.Read())
                        {
                            if (inner.Name.Equals("ns:amt"))
                            {
                                amt = inner.ReadElementString();
                            }
                        }
                        Console.WriteLine("amt: {0}", amt);
                        inner.Close();
                        x = x + 1;
                    }

                }
                Console.WriteLine("{0} transactions found", x.ToString());
                baseReader.Close();
                file.Close();
            }
            catch (XmlException xe)
            {
                Console.WriteLine("XML Parsing Error: " + xe);
            }
            catch (IOException ioe)
            {
                Console.WriteLine("File I/O Error: " + ioe);
            }
        }
    }
}

【问题讨论】:

    标签: c# xml


    【解决方案1】:

    从您的示例代码看来,您可以使用LINQ to XML,这将是您问题的更简洁的解决方案:

        XDocument xDoc = XDocument.Load(@"C:\Data.xml");
        string amt = xDoc.Descendants("salesTaxAmt")
                         .Elements("amt")
                         .Single().Value;
    

    如果你可以使用它,LINQ to XML 绝对是你的选择,它提供了一种简单而强大的语法来从 XML 中检索数据,并且可以很好地与 LINQ to 对象配合使用。

    【讨论】:

    • 我使用的 XML 片段没有根元素,只有多个 tranactionUnit 元素。我将如何使用 Linq to XML 遍历每个交易单元并提取数据?
    • 最简单的方法是将您的 XML 片段放在一个字符串中,在其周围添加一个根元素 "&lt;data&gt;" + myXML + "&lt;/data&gt;",使用 XDocument.Parse() 加载此数据,然后您就可以对其进行解析了。
    【解决方案2】:

    获取节点值的更简单方法是使用 XPath。

    请注意,这只有在将路径指向要检索其值的节点时才可能。

    
    private string GetNodeValue(string xmlFilePath, string xpath)
    {
        string nodeValue = string.Empty;
        using (StreamReader reader = new StreamReader(xmlFilePath))
        {
            XPathDocument xPathDocument = new XPathDocument(reader);
    
            XPathNavigator navigator = xPathDocument.CreateNavigator();
            XPathNodeIterator iter = navigator.Select(xpath);
            iter.MoveNext();
            nodeValue = iter.Current.Value;
            //iter.Current.ValueAsDouble;
        }
    
        return nodeValue;
    }
    

    您的示例 xml 的用法应该是:

    
    string nodeValue = GetNodeValue(@"C:\Data.xml", "//transactionUnit/transactionDetails/salesTaxAmt/amt");
    

    此外,您可以将方法重命名为“GetNodeValueAsDouble”并使用iter.Current.ValueAsDouble 而不是iter.Current.Value 来获取双精度值。


    更多信息

    【讨论】:

    • 我喜欢使用 XPath 来支持 Linq,因为它是一种用于查询 XML 的开放且标准化的方法。它也独立于使用的编程语言。
    猜你喜欢
    • 1970-01-01
    • 2013-07-08
    • 2021-07-09
    • 1970-01-01
    • 2014-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多