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.
Related
I am new to XDocument but I have been looking around for a solution to this problem which I couldn't get to fix.
I need to load some kind of XML files (PNML) that comes this way:
<pnml xmlns="http://www.pnml.org/version-2009/grammar/pnml">
<net id="id" type ="http://www.pnml.org/version-2009/grammar/ptnet">
..........</net> </pnml>
And I couldn't get to load these kind of files unless I add "xmlns" as an Attribute to the node net .
Meanwhile, the files I create myself has this xmlns attribute, and I can load them without problems.
While, files that are generated from some other software that I need to be able to use from my software doesn't has this "xmlns" attribute, and if I add it myself to the files generated by this software, I can load those files.
Here's the code I am using to Load :
XDocument doc = XDocument.Load(file);
XNamespace ns = #"http://www.pnml.org/version-2009/grammar/pnml";
foreach (XElement element in doc.Element(ns + "pnml")
.Elements("net").Elements("page").Elements("place"))
{ // Do my loading to "place" nodes for example }
But whenever I try to load a file, it just skips my "foreach" statement, and if I add some line before "foreach" like:
string id= (string) doc.Element(ns + "pnml")
.Element("net").Attribute("id");
it says:
Object reference not set to an instance of an object.
Here's an example of a file generated by my code and also can be read from my code:
<?xml version="1.0" encoding="utf-8"?>
<pnml xmlns="http://www.pnml.org/version-2009/grammar/pnml">
<net id="netid" type="http://www.pnml.org/version-2009/grammar/ptnet" xmlns="">
nodes and information </net> </pnml>
NOTE: I use this code to save my files:
XNamespace ns = #"http://www.pnml.org/version-2009/grammar/pnml";
XDocument doc = new XDocument
(
new XElement(ns+"pnml"
, new XElement("net",new XAttribute("id", net_id), ...));
I found a way to save my files without this "xmlns" attribute, but once I omit it, I can't load it from my code. And the first example I wrote is the standard format and I really need to get ride of the "xmlns" problem.
EDIT: I'm sorry if you got confused, what I want is to be able to load the standard PNML files that doesn't have thise "xmlns" attribute within the "net" node.
What you're missing is that element namespaces are inherited from their parents.
So your XML:
<pnml xmlns="http://www.pnml.org/version-2009/grammar/pnml">
<net id="id" type ="http://www.pnml.org/version-2009/grammar/ptnet">
...
Contains two elements. One is pnml with the namespace http://www.pnml.org/version-2009/grammar/pnml, and the child is net which also has the namespace http://www.pnml.org/version-2009/grammar/pnml.
With this in mind, your query on the existing XML should be:
doc.Element(ns + "pnml").Elements(ns + "net")...
And your code to generate the XML should be:
new XElement(ns + "pnml",
new XElement(ns + "net", new XAttribute("id", net_id), ...));
Try something like this
var result = doc.Element(ns + "pnml").Descendants().Where(x=>x.Name.LocalName=="net")
I have some XML that has been generated by default conversion of a JSON response stream, and so doesn't have a namespace declared. I now want to retrieve a specific node from that XML by using the SelectSingleNode method, but cannot specify the namespace because there isn't one specified. What should I use to register a namespace?
My XML looks like this:
<root type="object">
<customer type="object">
<firstName type="string">Kirsten</firstName>
<lastName type="string">Stormhammer</lastName>
</customer>
</root>
The code I have tried is:
XmlDocument document = new XmlDocument();
document.LoadXml(customerXml);
XmlNamespaceManager manager = new XmlNamespaceManager(document.NameTable);
manager.AddNamespace("x", "http://www.w3.org/TR/html4/"); // What should I use here?
XmlNode customerNode= document.SelectSingleNode("x:customer");
This always returns null.
I have also tried using the local-name qualifier (without using a namespace manager):
XmlDocument document = new XmlDocument();
document.LoadXml(customerXml);
XmlNode customerNode= document.SelectSingleNode("/*[local-name()='root']/*[local-name()='customer']");
This also returns null.
Then you can do in a much simpler way, without involving XmlNamespaceManager and namespace prefix :
XmlDocument document = new XmlDocument();
document.LoadXml(customerXml);
XmlNode customerNode= document.SelectSingleNode("/root/customer");
[.NET fiddle demo]
I am looking for a best way to exctract a local path of the schema without using regex.
Sample:
<?xml version="1.0"?>
<ord:order xmlns:ord="http://example.org/ord"
xmlns:prod="http://example.org/prod"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://example.org/prod chapter05prod.xsd
http://example.org/ord chapter05ord.xsd">
<items>
<prod:product>
<number xsi:type="xs:short">557</number>
<name>Short-Sleeved Linen Blouse</name>
<size xsi:nil="true"/>
</prod:product>
</items>
or
xsi:schemaLocation="http://example.org/prod \\RandomFolder\New\chapter05prod.xsd">
or
xsi:schemaLocation="chapter05prod.xsd">
I would like to get a local path for *.xsd file. Is there any way to do this using a xml parser or xmlResolver or in some other way that is not using a regex?
Edit: I am looking for a most generic approach to get a path for external .xsd path references.
Another example:
xsi:noNamespaceSchemaLocation="file://C://Documents and Settings//All Users//Application Data//My Application//MyData.xsd"
You can use XPath:
using System;
using System.Xml;
using System.Xml.XPath;
Since the data you want is inside an attribute that is qualified by a namespace, you would need to register the namespace before performing an XPath expression. In your case, you can ignore the namespace and use an expression like this one:
//#*[local-name()='schemaLocation']
which will select the attribute node which has a local name of schemaLocation (ignoring its prefix).
Parse your XML file and get the root (document) element:
XmlTextReader reader = new XmlTextReader("your-file.xml");
XmlDocument doc = new XmlDocument();
doc.Load(reader);
reader.Close();
XmlElement root = doc.DocumentElement;
Then use it to select all attributes named schemaLocation. There is only one, so you can use SelectSingleNode:
XmlNode schemaLocationAttribute = root.SelectSingleNode("//#*[local-name()='schemaLocation']");
The expression above contains the attribute. You can get its string contents using schemaLocationAttribute.Value. From there you can split the contents using whitespace as the delimiter:
string[] components = schemaLocationAttribute.Value.Split(null);
And you will have the text that you want (chapter05prod.xsd) in components[1]:
Console.WriteLine (components[1]);
(Note: you can't always ignore XPath namespaces - if there were other attributes named schemaLocation in your file with a different prefix or with no prefix, they would also be selected by that XPath expression and this solution would fail.)
Hi all i am creating an application to generate an XML file dynamically. In this i would like to add schemalocation and XSI to the XML Root how can i do this. I would like to add the following
xmlns="http://www.irs.gov/efile"
xsi:SchemaLocation="http://www.irs.goc/efile ReturnData941.xsd"
and
xmlns:xsi="http://www.w3.org/2001/XMLSchema-Instance"
This is my sample XML code that was generated dynamically
XmlDocument doc = new XmlDocument();
XmlNode docNode = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
doc.AppendChild(docNode);
XmlNode returnData = doc.CreateElement("ReturnData");
XmlAttribute documnetCount = doc.CreateAttribute("documentCount"); // after this i would like to add that schema
returnData.Attributes.Append(documnetCount);
So that i should get my XML as follows
<?xml version="1.0" encoding="UTF-8"?>
<ReturnData documentCount="" xsi:SchemaLocation="http://www.irs.goc/efile ReturnData941.xsd" xmlns="http://www.irs.gov/efile" xmlns:xsi="http://www.w3.org/2001/XMLSchema-Instance" />
I think you just need add a attribute like
XmlAttribute attr = doc.CreateAttribute("xsi", "schemaLocation", " ");
attr.Value = "http://www.irs.goc/efile ReturnData941.xsd";
returnData.Attributes.Append(attr);
I wonder if this is the best way of approaching things? Many validation APIs allow you to specify the schema location and instance document location independently, and that's likely to be more efficient than storing the schema location within the instance.
Generally I'm sceptical about xsi:schemaLocation anyway. If you're validating the instance, that's often because you don't trust it, and if you don't trust it, why should you trust its xsi:schemaLocation?
I use .NET XML technologies quite extensively on my work. One of the things the I like very much is the XSLT engine, more precisely the extensibility of it. However there one little piece which keeps being a source of annoyance. Nothing major or something we can't live with but it is preventing us from producing the beautiful XML we would like to produce.
One of the things we do is transform nodes inline and importing nodes from one XML document to another.
Sadly , when you save nodes to an XmlTextWriter (actually whatever XmlWriter.Create(Stream) returns), the namespace definitions get all thrown in there, regardless of it is necessary (previously defined) or not. You get kind of the following xml:
<root xmlns:abx="http://bladibla">
<abx:child id="A">
<grandchild id="B">
<abx:grandgrandchild xmlns:abx="http://bladibla" />
</grandchild>
</abx:child>
</root>
Does anyone have a suggestion as to how to convince .NET to be efficient about its namespace definitions?
PS. As an added bonus I would like to override the default namespace, changing it as I write a node.
Use this code:
using (var writer = XmlWriter.Create("file.xml"))
{
const string Ns = "http://bladibla";
const string Prefix = "abx";
writer.WriteStartDocument();
writer.WriteStartElement("root");
// set root namespace
writer.WriteAttributeString("xmlns", Prefix, null, Ns);
writer.WriteStartElement(Prefix, "child", Ns);
writer.WriteAttributeString("id", "A");
writer.WriteStartElement("grandchild");
writer.WriteAttributeString("id", "B");
writer.WriteElementString(Prefix, "grandgrandchild", Ns, null);
// grandchild
writer.WriteEndElement();
// child
writer.WriteEndElement();
// root
writer.WriteEndElement();
writer.WriteEndDocument();
}
This code produced desired output:
<?xml version="1.0" encoding="utf-8"?>
<root xmlns:abx="http://bladibla">
<abx:child id="A">
<grandchild id="B">
<abx:grandgrandchild />
</grandchild>
</abx:child>
</root>
Did you try this?
Dim settings = New XmlWriterSettings With {.Indent = True,
.NamespaceHandling = NamespaceHandling.OmitDuplicates,
.OmitXmlDeclaration = True}
Dim s As New MemoryStream
Using writer = XmlWriter.Create(s, settings)
...
End Using
Interesting is the 'NamespaceHandling.OmitDuplicates'
I'm not sure this is what you're looking for, but you can use this kind of code when you start writing to the Xml stream:
myWriter.WriteAttributeString("xmlns", "abx", null, "http://bladibla");
The XmlWriter should remember it and not rewrite it anymore. It may not be 100% bulletproof, but it works most of the time.