使用XMLReader访问具有重复名称的子节点

时间:2011-01-19 23:45:51

标签: c# xml

使用下面的XML片段,如何使用XMLReader访问节点<amt>的子节点<salesTaxAmt>?如果我遍历寻找节点名称“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);
            }
        }
    }
}

2 个答案:

答案 0 :(得分:3)

从您的示例代码看起来您​​可以使用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 objects很好地配合。

答案 1 :(得分:1)

获取节点值的一种更简单的方法是使用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来获取双倍值。


更多信息