I'm trying to parse an Atom feed programmatically. I have the atom XML downloaded as a string. I can load the XML into an XmlDocument. However, I can't traverse the document using XPath. Whenever I try, I get null.
I've been using this Atom feed as a test: http://steve-yegge.blogspot.com/feeds/posts/default
Calling SelectSingleNode() always returns null, except for when I use "/". Here is what I'm trying right now:
using (WebClient wc = new WebClient())
{
string xml = wc.DownloadString("http://steve-yegge.blogspot.com/feeds/posts/default");
XmlNamespaceManager nsMngr = new XmlNamespaceManager(new NameTable());
nsMngr.AddNamespace(string.Empty, "http://www.w3.org/2005/Atom");
nsMngr.AddNamespace("app", "http://purl.org/atom/app#");
XmlDocument atom = new XmlDocument();
atom.LoadXml(xml);
XmlNode node = atom.SelectSingleNode("//entry/link/app:edited", nsMngr);
}
I thought it might have been because of my XPath, so I've also tried a simple query of the root node since I knew the root should work:
// I've tried both with & without the nsMngr declared above
XmlNode node = atom.SelectSingleNode("/feed");
No matter what I do, it seems like it can't select anything. Obviously I'm missing something, I just can't figure out what. What is it that I need to do in order to make XPath work on this Atom feed?
EDIT
Although this question has an answer, I found out this question has an almost exact duplicate: SelectNodes not working on stackoverflow feed
While the C# implementation may allow default namespaces (I don't know), the XPath 1.0 spec doesn't. So, give "Atom" its own prefix:
nsMngr.AddNamespace("atom", "http://www.w3.org/2005/Atom");
And change your XPath appropriately:
XmlNode node = atom.SelectSingleNode("//atom:entry/atom:link/app:edited", nsMngr);
Load XML from a string and lookup for any 'Errors/Error' nodes.
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlResult);
XmlNamespaceManager nm = new XmlNamespaceManager(xmlDoc.NameTable);
nm.AddNamespace("ns", "http://somedomain.com/namespace1/2"); //ns - any name, make sure it is same in the below line
XmlNodeList errors = xmlDoc.SelectNodes("/ns:*//ns:Errors/ns:Error", nm);
-Mathulan
Related
So I just started using c# about a day ago and haven't had too many issues with it so far but I'm working on an bot for Discord that will pull Pokemon info from an api. I'm currently stuck on traversing through the xml. Here's part of the xml I'm trying to work with:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<stats>
<stat>
<url>https://pokeapi.co/api/v2/stat/6/</url>
<name>speed</name>
</stat>
<effort>0</effort>
<base_stat>100</base_stat>
</stats>
</root>
That's basically an abridged version of my xml doc but there are multiple nodes for "stats". I want to loop the the stats nodes and pull the name of the stat and the value for base stat. Everything I've tried so far throws a null exception error. I having trouble trying to understand how to correctly parse xml so any help would be greatly aprreciated. Also just for extra info I'm working with XmlDocuments. Here's basically what ive tried so far:
XmlDocument pokemon = new XmlDocument();
pokemon.Load("c:\\document.xml");
XmlNodeList xmlNodes = pokemon.SelectNodes("/root/stats");
int count = 0;
foreach (XmlNode xmlNode in xmlNodes)
{
temp.stats[count].val = xmlNode["/stat/name"].InnerText;
temp.stats[count++].num = xmlNode["base_stat"].InnerText;
}
temp is of type poke and stats is just a type I made that has two strings in it, one for the name of the stat and another for the value of the stat. I was able to access other things from the xml document perfectly fine but I'm having trouble pulling from nodes that share the same name.
I believe this will set you on the right path:
XmlNodeList xmlNodes = pokemon.SelectNodes(#"//root/stats");
int count = 0;
foreach (XmlNode xmlNode in xmlNodes)
{
temp.stats[count].val = xmlNode.SelectSingleNode("stat/name").InnerText;
temp.stats[count++].num = xmlNode.SelectSingleNode("base_stat").InnerText;
}
First, to reference the root node with XPath, you need the double forward slashes //. Secondly, you need to use xmlNode.SelectSingleNode(string xPath), and your XPath shouldn't have the leading forward slash.
I'm working on an WinRT App and I should ready some XML with a namespace in it. Now this was ok with the old .NET, but now there is no XmlDocument.NameTable anymore. So how can I create an XmlNamespaceManager?
var XmlDoc = new XmlDocument();
XmlDoc.Load(new FileStream("XMLFile1.xml",FileMode.Open,FileAccess.Read));
var nsm = new XmlNamespaceManager(XmlDoc.NameTable);
nsm.AddNamespace("s", "http://api.facebook.com/1.0/");
It's much easier to handle namespaces with LINQ to XML, which I believe is what you can use in Windows 8:
XDocument doc = XDocument.Load(...);
XNamespace ns = "http://api.facebook.com/1.0/";
XElement element = doc.Root.Element(ns + "foo");
Read a good LINQ to XML introduction or tutorial, and you should see how to handle namespaces - but it really is significantly simpler than with XmlDocument. You simply don't need namespace managers any more! (There may be some cases where they're still useful - I'm not sure - but I certainly can't remember using them myself with LINQ to XML.)
Some other questions have asked how to use Xpath to query XML documents with a default namespace. The answer is to use a namespace manager to create an alias for the default namespace, and use that alias in your xpaths.
However, what if you don't know the URI of the default namespace in advance? How do you find it out from the XML document?
var doc = XDocument.Parse(myXml);
XNamespace ns = doc.Root.GetDefaultNamespace();
If you are using XmlDocument, you can get the default namespace by checking NamespaceURI of the root element:
var document = new XmlDocument();
document.LoadXml("<root xmlns='http://java.sun.com/xml/ns/j2ee'></root>");
var defaultNamespace = document.DocumentElement.NamespaceURI;
Assert.IsTrue(defaultNamespace == "http://java.sun.com/xml/ns/j2ee");
You could try using XmlNamespaceManager.DefaultNamespace to get it.
http://msdn.microsoft.com/en-us/library/system.xml.xmlnamespacemanager.defaultnamespace.aspx
I know this is an old topic, but I had the same problem, using the XmlDocument class, as I wanted to know the Default Namespace and a prefixed namespace.
I could get both namespaces using the same Method.
string prefixns = element.GetNamespaceOfPrefix("prefix");
string defaultns = element.GetNamespaceOfPrefix("");
this seems to work for me getting both namespaces on a XmlElement.
Edit: This is a XmlNode Method, so should also work on Attributes
The simplest way to do it
XmlDocument xDoc = new XmlDocument();
xDoc.Load(uriPath);
Console.WriteLine(xDoc.NamespaceURI);
The function "WriteStartElement" does not return anything. I find this a little bizzare.
So up until now I have been doing it like this.
XmlDocument xmlDoc = new XmlDocument();
XmlTextWriter xmlWriter = new XmlTextWriter(m_targetFilePath, System.Text.Encoding.UTF8);
xmlWriter.Formatting = Formatting.Indented;
xmlWriter.WriteProcessingInstruction("xml", "version='1.0' encoding='UTF-8'");
xmlWriter.WriteStartElement("client");
xmlWriter.Close();
xmlDoc.Load(m_targetFilePath);
XmlElement root = xmlDoc.DocumentElement;
Saving the doc, then reloading it to get hold of the start element so i can write attributes to it. Does anybody know the correct way of doing this because I'm pretty sure what I'm doing isn't right.
I tried to use xmlWriter.AppendChild() but it doesnt seem to write out anything. :(
If you are using 3.5 or higher, XDocument would make you fall in love.
Have you tried something like this ?
// add the root node
xmlWriter.WriteStartElement("client");
// add the attribute to root node
xmlWriter.WriteStartAttribute("foo");
// add the value of the attribute
xmlWriter.WriteValue("attribute value...");
// close the attribute to root node
xmlWriter.WriteEndAttribute();
// close the root node
xmlWriter.WriteEndElement();
Have you looked at using XmlSerializer? Create a class to hold all your data, create an instance of your class and then use XmlSerializer to write it out to an XML file.
i am using a WSDL file to create a the proxy class file, this service has a big Enumeration. the description for each enum value is in documentation section, how can i programatically read that section?
A WSDL file is always an XML file, so you can open it and read the elements data. For example, given the eBay Services WSDL file, you can query the documentation of the value COD of the enumeration BuyerPaymentMethodCodeType like this:
XmlDocument wsdlDoc = new XmlDocument();
wsdlDoc.Load(#"D:\temp\eBaySvc.wsdl");
XmlNamespaceManager nsMgr = new XmlNamespaceManager(wsdlDoc.NameTable);
nsMgr.AddNamespace("xs", "http://www.w3.org/2001/XMLSchema");
XmlNode node = wsdlDoc.SelectSingleNode("//xs:simpleType[#name='BuyerPaymentMethodCodeType']/xs:restriction/xs:enumeration[#value='COD']/xs:annotation/xs:documentation", nsMgr);
string description = node.InnerText;