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);
Related
I'm putting this here because I saw a lot of Q&A for XML on StackOverflow while trying to solve my own problems, and figured that once I'd found it, I'd post what I found so when someone else needs some XML help, this might help them.
My goal: To create an XML document that contains the following XML Declaration, Schema & Namespace Information:
<?xml version="1.0" encoding="UTF-8"?>
<abc:abcXML xsi:schemaLocation="urn:abcXML:v12 http://www.test.com/XML/schemas/v12/abcXML_v12.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ase="urn:abcXML:v12">
I'd already done it in Python for a quick prototype using minidom, and it was very simple. I needed to do it in a .NET language though (C#), because that's what the business calls for. I'm quite familiar with C#, but I've always stayed away from processing XML with it because I honestly don't have an in-depth grasp of XML and it's guidelines. Today, I had to face my demons.
Here's how I did it:
The first part is simple enough - create a document, and create a DocumentElement for the root (there's a catch here which I get to later):
XmlDeclaration xmlDeclaration = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
XmlElement root = doc.DocumentElement;
doc.InsertBefore(xmlDeclaration, root);
The next part seems simple enough - create an element, give it a prefix, name and URI, then append it to the document. I thought this would work, but it doesn't (this is where the minimal understanding of XML comes into play):
XmlElement abcXML = xmlDoc.CreateElement("ase", "abcXML", "urn:abcXML:r38 http://www.w3.org/2001/XMLSchema-instance");
XmlAttribute xmlAttr = xmlDoc.CreateAttribute("xsi:schemaLocation", "urn:abcXML:v12 http://www.test.com/XML/schemas/v12/abcXML_v12.xsd");
abcXML.AppendChild(xmlAttr);
xmlDoc.AppendChild(abcXML);
I tried to use doc.LoadXml() and doc.CreateDocumentFragment() and write my own declarations. No - I would get "Unexpected end of file". For those interested in XmlDocumentFragment: https://learn.microsoft.com/en-us/dotnet/api/system.xml.xmldocumentfragment.innerxml?view=netcore-3.1
This Microsoft article about XML Schemas and Namespaces didn't directly help me: https://learn.microsoft.com/en-us/dotnet/standard/data/xml/including-or-importing-xml-schemas
After doing more reading on XML, and going through the documentation for XmlDocument, XmlElement and XmlAttribute, this is the solution:
XmlElement abcXML = xmlDoc.CreateElement("ase", "abcXML", "urn:abcXML:r38");
XmlAttribute xmlAttr = xmlDoc.CreateAttribute("xsi:schemaLocation", "http://www.w3.org/2001/XMLSchema-instance");
xmlAttr.InnerXml = "urn:abcXML:v12 http://www.test.com/XML/schemas/v12/abcXML_v12.xsd";
abcXML.Attributes.Append(xmlAttr);
xmlDoc.AppendChild(abcXML);
Now you can add the elements to your document like so:
XmlElement header = doc.CreateElement(string.Empty, "Header", string.Empty);
abcXML.AppendChild(header);
To save the document, I used:
xmlDoc.Save(fileLocation);
I compared my output to the sample I had, and after comparing the file contents, I had succeeded in matching it. I provided the output to the client, they uploaded it into application they were using, and it failed: Row 1, Column 1 - Unexpected Character.
I had a suspicion it was encoding, and I was right. Using xmlDoc.Save(fileLocation) is correct, but it generates a UTF-8 file with the Byte Order Mark (BOM) at Row 1, Column 1. The XML parsing function in the application doesn't expect that, so the process failed. To fix that, I used the following method:
Encoding enc = new UTF8Encoding(false); /* This creates a UTF-8 encoding without the BOM */
using (System.IO.TextWriter tw = new System.IO.StreamWriter(filePath, false, enc))
{
xmlDoc.Save(tw);
}
return true;
I generated the file again, sent it to the client, and it worked first go.
I hope someone finds this to be useful.
For complicated namespaces it is simpler to just parse the xml string. I like using xml linq. You sample xml is wrong. The namespace is "ase" (not abc).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<ase:abcXML xsi:schemaLocation=\"urn:abcXML:v12 http://www.test.com/XML/schemas/v12/abcXML_v12.xsd\"" +
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" +
" xmlns:ase=\"urn:abcXML:v12\">" +
"</ase:abcXML>";
XDocument doc = XDocument.Parse(xml);
XElement root = doc.Root;
XNamespace nsAse = root.GetNamespaceOfPrefix("ase");
}
}
}
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.)
I'm using the following code to initialise an XmlDocument
XmlDocument moDocument = new XmlDocument();
moDocument.AppendChild(moDocument.CreateXmlDeclaration("1.0", "UTF-8", null));
moDocument.AppendChild(moDocument.CreateElement("kml", "http://www.opengis.net/kml/2.2"));
Later in the process I write some values to it using the following code
using (XmlWriter oWriter = oDocument.DocumentElement.CreateNavigator().AppendChild())
{
oWriter.WriteStartElement("Placemark");
//....
oWriter.WriteEndElement();
oWriter.Flush();
}
This ends up giving me the following xml when I save the document
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Placemark xmlns="">
<!-- -->
</Placemark>
</kml>
How can I get rid of the empty xmlns on the Placemark element?
--EDITED TO SHOW CHANGE TO HOW PLACEMARK WAS BEING WRITTEN--
If I put the namespace in the write of placemark then non of the elements are added to the document.
I have fixed the issue by creating the document with the following code (no namespace in the document element)
XmlDocument moDocument = new XmlDocument();
moDocument.AppendChild(moDocument.CreateXmlDeclaration("1.0", "UTF-8", null));
moDocument.AppendChild(moDocument.CreateElement("kml"));
And by saving it with the following code to set the namespace before the save
moDocument.DocumentElement.SetAttribute("xmlns", msNamespace);
moDocument.Save(msFilePath);
This is valid as the namespce is only required in the saved xml file.
This is an old post, but just to prevent future bad practice; you should never declare the xmlns namespace in an XML document, so this may be the cause why you get empty nodes since you are doing something the XmlDocument is not supposed to do.
The prefix xmlns is used only to declare namespace bindings and is by
definition bound to the namespace name http://www.w3.org/2000/xmlns/.
It MUST NOT be declared . Other prefixes MUST NOT be bound to this
namespace name, and it MUST NOT be declared as the default namespace.
Element names MUST NOT have the prefix xmlns.
Source: http://www.w3.org/TR/REC-xml-names/#ns-decl
The following code worked for me (source):
XmlSerializer s = new XmlSerializer(objectToSerialize.GetType());
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("","");
s.Serialize(xmlWriter, objectToSerialize, ns);
oWriter.WriteStartElement("Placemark"); should work, because the parent node already has the right namespace.
Did you try:
oWriter.WriteStartElement("kml", "Placemark", "kml");
You needed
oWriter.WriteStartElement("Placemark", "http://www.opengis.net/kml/2.2");
otherwise the Placemark element gets put in the null namespace, which is why the xmlns="" attribute is added when you serialize the XML.
how to add element to a xml file using asp.net& c#.net inweb application
Here's an example of adding a new element to the root node:
XDocument doc = XDocument.Load("test.xml");
doc.Root.Add(new XElement("someNode", "some node value"));
doc.Save("test.xml");
Load the document using XmlDocument class and then modify it as needed. Reference documentation and examples here.
You can use XmlDocument.CreateElement method to create it and then to append it
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