I'm reading a remote XML file and once the XML is loaded into an XMLDocument object I need to traverse through it and extract the values that my application requires. My code is as follows:
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load("http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml");
XmlNamespaceManager nsMan = new XmlNamespaceManager(xmlDocument.NameTable);
nsMan.AddNamespace("gesmes", "http://www.gesmes.org/xml/2002-08-01");
nsMan.AddNamespace("", "http://www.ecb.int/vocabulary/2002-08-01/eurofxref");
XmlNodeList xmlNodeList = xmlDocument.DocumentElement.SelectNodes("/gesmes:Envelope/Cube/Cube/Cube", nsMan);
HttpContext.Current.Response.Write("The numner of nodes is " + xmlNodeList.Count); //it's always zero
However the problem I'm getting is that XmlNodeList always returns zero nodes, whereas if I evaluate the XPath expression in XMLSpy I get the nodes I require.
For reference the XML looks like:
<?xml version="1.0" encoding="UTF-8"?>
<gesmes:Envelope xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01" xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref">
<gesmes:subject>Reference rates</gesmes:subject>
<gesmes:Sender>
<gesmes:name>European Central Bank</gesmes:name>
</gesmes:Sender>
<Cube>
<Cube time='2011-07-27'>
<Cube currency='USD' rate='1.4446'/>
<Cube currency='GBP' rate='0.88310'/>
</Cube>
</Cube>
</gesmes:Envelope>
I want to return the Cube nodes for USD and GBP.
Any ideas you clever people?
Thanks
Al
While you definitely can work with namespaces and XPath in the XmlDocument API, I would strongly advise you to use LINQ to XML (.NET 3.5) if at all possible:
string url = "http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml";
XDocument doc = XDocument.Load(url);
XNamespace gesmes = "http://www.gesmes.org/xml/2002-08-01";
XNamespace ns = "http://www.ecb.int/vocabulary/2002-08-01/eurofxref";
var cubes = doc.Descendants(ns + "Cube")
.Where(x => x.Attribute("currency") != null)
.Select(x => new { Currency = (string) x.Attribute("currency"),
Rate = (decimal) x.Attribute("rate") });
foreach (var result in cubes)
{
Console.WriteLine("{0}: {1}", result.Currency, result.Rate);
}
Related
I am trying to divide an XML file into parts
I have an XML file like this
<?xml version="1.0" encoding="utf-8"?>
<RegistrationOpenData xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://example.gov">
<Description>Registration data is collected by ABC XYZ</Description>
<InformationURL>http://www.example.com/html/hpd/property-reg-unit.shtml</InformationURL>
<SourceAgency>ABC Department of Housing</SourceAgency>
<SourceSystem>PREMISYS</SourceSystem>
<StartDate>2016-02-29T00:03:06.642772-05:00</StartDate>
<EndDate i:nil="true" />
<Registrations>
<Registration xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<RegistrationID>1</RegistrationID>
<BuildingID>1A</BuildingID>
<element1>E11</element1>
<element2>E21</element2>
<element3>E31</element3>
<element4>E41</element4>
</Registration>
<Registration xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<RegistrationID>2</RegistrationID>
<BuildingID>2A</BuildingID>
<element1>E21</element1>
<element2>E22</element2>
<element3>E32</element3>
<element4>E42</element4>
</Registration>
</Registrations>
</RegistrationOpenData>
And I am trying to fetch the number of nodes trough this code
XmlDocument doc = null;
doc = new XmlDocument();
doc.Load(#"D:\Registrations20160229.xml");
XmlNodeReader nodeReader = new XmlNodeReader(doc);
XmlElement root = doc.DocumentElement;
XmlNodeList elemList = root.GetElementsByTagName("Registration");
int totalnode = elemList.Count;
int nodehalf = totalnode / 2;
MessageBox.Show(nodehalf.ToString());
But after this I am unable to proceed, This code I have used to calculate number of Registration Nodes and then made them into half, now I don't know how to proceed further to split this file, I have total of 158718 entries (Registration Nodes) inside the file (sometimes even more) and I am trying to break all into parts, maybe 3 to 4 parts.
Try this , it should not load whole xml to memory
using(XmlReader reader = XmlReader.Create(new FileStream(#"D:\Registrations20160229.xml" , FileMode.Open))){
while (reader.Read())
{
if(reader.NodeType == XmlNodeType.Element && reader.Name == "Registration")
counter++;
}
Console.WriteLine(counter);
}
How to parse through XML file using a node Id. I want to get to <Rate>0.8988</Rate> node of <rate id="USDEUR">
<results>
<rate id="USDEUR">
<Name>USD/EUR</Name>
<Rate>0.8988</Rate>
<Date>5/27/2016</Date>
<Time>6:56pm</Time>
<Ask>0.8989</Ask>
<Bid>0.8988</Bid>
</rate>
<rate id="USDJPY">
<Name>USD/JPY</Name>
<Rate>110.1250</Rate>
<Date>5/27/2016</Date>
<Time>6:53pm</Time>
<Ask>110.1500</Ask>
<Bid>110.1250</Bid>
</rate>
</results>
This is what I am able to do so far.
string sitemapurl = #"http://example.com/xmlforexrates";
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(sitemapurl);
XmlNodeList nodeIds = xmlDoc.SelectNodes("/results/rate");
Right now it's getting all the <rate> nodes in the NodeList. I just wanted to get node on Id based for example only <rate id="USDEUR">
Please help me do this. Thanks
Using XPath, you can do it like this:
XmlNodeList nodeIds = xmlDoc.SelectNodes("/results/rate[#id='USDEUR']/Rate/text()");
This is pretty trivial using LINQ to XML.
var doc = XDocument.Load("http://example.com/xmlforexrates");
var rate = (decimal)doc
.Descendants("rate")
.Where(x => (string) x.Attribute("id") == "USDEUR")
.Elements("Rate")
.Single();
See this fiddle for a working demo.
my Code looks something like this, I want to print the value of the currency but i donot know where i am wrong
XmlDocument xdoc = new XmlDocument();
xdoc.Load("filepath");
XmlNodeList nodes = xdoc.SelectNodes("//gesmes/gesmes");
foreach (XmlNode node in nodes)
{
Console.WriteLine(node["currency"]);
}
My Xml document looks like this
<gesmes:Envelope xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01"
xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref">
<gesmes:subject>Reference rates</gesmes:subject>
<gesmes:Sender>
<gesmes:name>European Central Bank</gesmes:name>
</gesmes:Sender>
<Cube>
<Cube time="2014-07-21">
<Cube currency="USD" rate="1.3518"/>
<Cube currency="JPY" rate="136.97"/>
<Cube currency="BGN" rate="1.9558"/>
</Cube>
</Cube>
</gesmes:Envelope>
there are multiple things wrong with your code:
Namespaces
you have to add a namespace manager and add the namespaces defined in your xml
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xdoc.NameTable);
nsmgr.AddNamespace("gesmes", "http://www.gesmes.org/xml/2002-08-01");
nsmgr.AddNamespace("lo", "http://www.ecb.int/vocabulary/2002-08-01/eurofxref");
notice how I added the default namespace with the lo alias to be able to query it using XPath later on
XPath
what are you trying to select?
gesmes is a namespace in your document not a node you can select. From your question I guess you want to select Cubes containing the currency attribute like so:
XmlNodeList nodes = xdoc.SelectNodes("//lo:Cube[#currency]", nsmgr);
notice that you need to include the namespace manager
Value
the value you are looking for is not a Node Value like
<Cube currency="USD">1.3518</Cube>
would be but an attribute value
select it using
node.Attributes["currency"].Value;
put together
XmlDocument xdoc = new XmlDocument();
xdoc.Load("filepath");
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xdoc.NameTable);
nsmgr.AddNamespace("gesmes", "http://www.gesmes.org/xml/2002-08-01");
nsmgr.AddNamespace("lo", "http://www.ecb.int/vocabulary/2002-08-01/eurofxref");
XmlNodeList nodes = xdoc.SelectNodes("//lo:Cube[#currency]", nsmgr);
foreach (XmlNode node in nodes)
{
Console.WriteLine(node.Attributes["rate"].Value);
}
Console.ReadKey();
I don't how to extract the values from XML document, and am looking for some help as I'm new to C#
I am using XmlDocument and then XmlNodeList for fetching the particular XML document
Here is my code
XmlNodeList XMLList = doc.SelectNodes("/response/result/doc");
And my XML looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<response>
<result>
<doc>
<long name="LoadID">494</long>
<long name="EventID">5557</long>
<str name="XMLData"><TransactionDate>2014-05-28T14:17:31.2186777-06:00</TransactionDate><SubType>tblQM2222Components</SubType><IntegerValue title="ComponentID">11111</IntegerValue></str></doc>
<doc>
<long name="LoadID">774</long>
<long name="EventID">5558</long>
<str name="XMLData"><TransactionDate>2014-05-28T14:17:31.2186777-06:00</TransactionDate><SubType>tblQM2222Components</SubType><IntegerValue title="ComponentID">11111</IntegerValue></str></doc>
</result>
</response>
In this i have to fetch every the XMLData data that is under every doc tag and i have to fetch last doc tag EventID.
var xml = XDocument.Parse(xmlString);
var docs = xml.Root.Elements("doc");
var lastDocEventID = docs.Last()
.Elements("long")
.First(l => (string)l.Attribute("name") == "EventID")
.Value;
Console.WriteLine ("Last doc EventId: " +lastDocEventID);
foreach (var doc in docs)
{
Console.WriteLine (doc.Element("str").Element("TransactionDate").Value);
}
prints:
Last doc EventId: 5558
2014-05-28T14:17:31.2186777-06:00
2014-05-28T14:17:31.2186777-06:00
You can use two XPath expressions to select the nodes you want. To answer each part of your question in turn:
To select all of the XMLData nodes:
XmlNodeList XMLList
= doc.SelectNodes("/response/result/doc/str[#name='XMLData']");
To select the last EventId:
XmlNode lastEventIdNode =
doc.SelectSingleNode("/response/result/doc[position() =
last()]/long[#name='EventID']");
If not all doc nodes are guaranteed to have an event id child node, then you can simply:
XmlNodeList eventIdNodes =
doc.SelectNodes("/response/result/doc[long[#name='EventID']]");
XmlNode lastNode = eventIdNodes[eventIdNodes.Count - 1];
That should give you what you've asked for.
Update;
If you want the XML data inside each strXml element, you can use the InnerXml property:
XmlNodeList xmlList
= doc.SelectNodes("/response/result/doc/str[#name='XMLData']");
foreach(XmlNode xmlStrNode in xmlList)
{
string xmlInner = xmlStrNode.InnerXml;
}
There's one result tag short in your xml.
Try using this. It's cleaner too imho
XmlNodeList docs = doc.SelectSingleNode("response").SelectSingleNode("result").SelectNodes("doc");
Then you can use a combination of SelectSingleNode, InnerText, Value to get the data from each XmlNode in your list.
For example if you want the EventID from the first doc tag:
int eventID = int.Parse(docs[0].SelectSingleNode("long[#name='EventID']").InnerText);
Suppose I have the following XML document, how to get the element value for a:name (in my sample, the value is Saturday 100)? My confusion is how to deal with the name space. Thanks.
I am using C# and VSTS 2008.
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<PollResponse xmlns="http://tempuri.org/">
<PollResult xmlns:a="http://schemas.datacontract.org/2004/07/FOO.WCF" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:name>Saturday 100</a:name>
</PollResult>
</PollResponse>
</s:Body>
</s:Envelope>
Use System.Xml.XmlTextReader class,
System.Xml.XmlTextReader xr = new XmlTextReader(#"file.xml");
while (xr.Read())
{
if (xr.LocalName == "name" && xr.Prefix == "a")
{
xr.Read();
Console.WriteLine(xr.Value);
}
}
It's easier if you use the LINQ to XML classes. Otherwise namespaces really are annoying.
XNamespace ns = "http://schemas.datacontract.org/2004/07/FOO.WCF";
var doc = XDocument.Load("C:\\test.xml");
Console.Write(doc.Descendants(ns + "name").First().Value);
Edit. Using 2.0
XmlDocument doc = new XmlDocument();
doc.Load("C:\\test.xml");
XmlNamespaceManager ns = new XmlNamespaceManager(doc.NameTable);
ns.AddNamespace("a", "http://schemas.datacontract.org/2004/07/FOO.WCF");
Console.Write(doc.SelectSingleNode("//a:name", ns).InnerText);
XPath is the direct way to get at bits of an XML document in 2.0
XmlDocument xml = new XmlDocument();
xml.Load("file.xml")
XmlNamespaceManager manager = new XmlNamespaceManager(xml.NameTable);
manager.AddNamespace("a", "http://schemas.datacontract.org/2004/07/FOO.WCF");
string name = xml.SelectSingleNode("//a:name", manager).InnerText;