Use XMLReader to access child nodes with duplicate names
Using the XML fragment below, how would I access the child node <amt>
of the node <salesTaxAmt>
using XMLReader? If I iterate over the nodes looking for a node name of "amt" I return the last node amount of <sourceCurrAmt>
which is 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>
Is the code below even the best way to do this?
Test Code:
using System;开发者_Python百科
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);
}
}
}
}
From your example code it looks like you can use LINQ to XML, this would be a more succinct solution for your problem:
XDocument xDoc = XDocument.Load(@"C:\Data.xml");
string amt = xDoc.Descendants("salesTaxAmt")
.Elements("amt")
.Single().Value;
If you can use it LINQ to XML should definitely be your choice, it provides an easy and powerful syntax for retrieving data from XML and plays nicely with LINQ to objects.
A simpler way to get the node value is to use XPath.
Note that this is possible only if you node the path to the node whose value is to be retreived.
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;
}
The usage for your sample xml should be:
string nodeValue = GetNodeValue(@"C:\Data.xml", "//transactionUnit/transactionDetails/salesTaxAmt/amt");
In addition, you could rename the method as 'GetNodeValueAsDouble' and use iter.Current.ValueAsDouble
instead of iter.Current.Value
to get the double value.
More Information
- XPathNavigator class
- XPathDocument class
精彩评论