Is it possible to create children using XmlDocument.CreateElement() and XmlNode.AppendChild() without specifying the namespace and have it use a "default" namespace?
Currently, if I create a root node with a namespace and don't specify the namespace on the every childnode, the output xml will define a blank namespace.
Below is what is generated if I don't specify the namespace for every element I create. Is there a shortcut where I don't have to specify the namespace every time?
<root xmlns="http://example.com">
<child1 xmlns="">
<child2 />
</child1>
</root>
Code:
XmlDocument doc = new XmlDocument();
var rootNode = doc.CreateElement("root", "http://example.com");
doc.AppendChild(rootNode);
var child1Node = doc.CreateElement("child1");
rootNode.AppendChild(child1Node);
var child2Node = doc.CreateElement("child2");
child1Node.AppendChild(child2Node);
If you have create your XML document, and you specify the same namespace for each element in the hierarchy - something like this:
XmlDocument doc = new XmlDocument();
const string xmlNS = "http://www.example.com";
XmlElement root = doc.CreateElement("root", xmlNS);
doc.AppendChild(root);
XmlElement child1 = doc.CreateElement("child1", xmlNS);
root.AppendChild(child1);
child1.AppendChild(doc.CreateElement("child2", xmlNS));
doc.Save(#"D:\test.xml");
then you'll get this output file:
<root xmlns="http://www.example.com">
<child1>
<child2 />
</child1>
</root>
The namespace on the <root> node is inherited down the hierarchy, unless the child elements define something else explicitly.
If you create a new XmlElement using doc.CreateElement and you don't specify a XML namespace, then of course, that new element, will have a blank namespace and thus this will be serialized into that XML document you had.
I am not aware of any way to specify a default namespace to use whenever you're creating a new element - if you specify one, the element will use that namespace - if you don't specify one, it's the blank namespace.
If you are using .NET 3.5, I suggest using LINQ to XML, (System.Xml.Linq). Use the XDocument, XElement, and XAttribute classes.
But marc_s's answer is correct, the namespace is inherited.
Related
Target XML I am trying to achieve:
<Row><Data ss:Type="String">value</Data></Row>
Output I am currently getting:
<Row xmlns=""><Data Type="Number">0</Data></Row>
I am trying to create that target XML code using the System.Xml library, but the namespace prefix is not showing up when I create new elements. Snippet of the code that is generating the above output:
XmlElement eRow = xDoc.CreateElement("Row");
XmlElement eData = xDoc.CreateElement("Data");
XmlAttribute xAt = xDoc.CreateAttribute("ss", "Type", null);
xAt.Value = "Number";
eData.Attributes.Append(xAt);
eData.InnerText = "0";
eRow.AppendChild(eData);
I am trying to append this XML to a file that already exists. I have loaded the file as
XmlDocument xTemp = new XmlDocument();
xTemp.Load(templatePath);
and there are already namespaces in DocumentElement.Attributes that have already declared the prefix that I want to use: <Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">. Essentially, I am trying to get the "ss" prefix to show up before "Type" like in the target I provided above. Additionally, the output is displaying xmlns="" as an attribute in the "Row" tag, something that I never added. I assume these are both issues with the namespace not being declared, but as mentioned above, it should already be declared in the original document that I loaded.
How can I generate the target XML code I want?
You have created your attribute xAt without specifying the namespace uri, which is equivalent to empty string namespace uri (see the corresponding MSDN doc here), that is certainly why you get the <Row xmlns="">
Actually you need to specify the exact namespace uri for it to work as you expect it.
Let me illustrate using the namespace uri you have given in your question (Illustration very similar to your initial code but might have a few small differences that you can easily modify).
String namespaceUri = "urn:schemas-microsoft-com:office:spreadsheet";
XmlDocument xDoc = new XmlDocument();
XmlElement workbook = xDoc.CreateElement("ss", "Workbook", namespaceUri);
XmlElement rows = xDoc.CreateElement("Rows");
At this step I can assume that I have an XmlDocument similar to what you have after initially loading your file. My XmlDocument has the workbook node as its DocumentElement, it uses the given prefix and namespace uri.
Now we can create the attribute:
var attribute = xDoc.CreateAttribute("ss", "Type", "urn:schemas-microsoft-com:office:spreadsheet");
attribute.Value = "String";
The namespace uri should be specified correctly otherwise it won't be correctly rendered. When this attribute is used, since the namespace it is refering to is found on the nesting element (workbook), it is not necessary to mention it again here, and the framework will automatically remove the reference to the namespace uri.
Now we can go ahead and create the Row and data elements and add the attribute to the collection of attributes of the Data element.
XmlElement eRow = xDoc.CreateElement("Row");
XmlElement eData = xDoc.CreateElement("Data");
eData.Attributes.Append(attribute);
eData.InnerText = "value";
eRow.AppendChild(eData);
rows.AppendChild(eRow);
workbook.AppendChild(rows);
xDoc.AppendChild(workbook);
We can then display the document, for example with:
Console.WriteLine(xDoc.OuterXml);
Result:
<ss:Workbook xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"><Rows><Row><Data ss:Type="String">value</Data></Row></Rows></ss:Workbook>
I hope this helps.
When I add xmls attribute to my root element this code through a exception at third line " Object reference not set to an instance of an object" but after removing xmls attribute from root element it it works fine.
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load("file.xml");
MessageBox.Show(xmlDoc.SelectSingleNode("person/name").InnerText);
here is my xmlfile
<?xml version="1.0" encoding="utf-8"?>
<person xmlns="namespace path">
<name>myname</name>
</person>
I want to know why it does not works after adding xmlns attribute to my root element. Do I have to use another method for parsing ?.
You need to add namespace messenger to resolve namespaces to your xml file.
Consider this example
XML File
<?xml version="1.0" encoding="utf-8"?>
<person xmlns="http://www.findpersonName.com"> // Could be any namespace
<name>myname</name>
</person>
and in your code
XmlDocument doc = new XmlDocument();
doc.Load("file.xml");
//Create an XmlNamespaceManager for resolving namespaces.
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("ab", "http://www.findpersonName.com");
MessageBox.Show(doc.SelectSingleNode("//ab:name", nsmgr).InnerText);
Note
If the XPath expression does not include a prefix, it is assumed
that the namespace URI is the empty namespace. If your XML includes a
default namespace, you must still add a prefix and namespace URI to
the XmlNamespaceManager; otherwise, you will not get a node selected.
For more information, see Select Nodes Using XPath Navigation.
XmlNamespaceManager ns = new XmlNamespaceManager(xmldoc.NameTable);
ns.AddNamespace("something", "http://or.other.com/init");
XmlNode node = xmldoc.SelectSingleNode("something:person/name", ns);
You may want to consider using XDocument and Linq to process your XML document.
The following example provides a rough example:
XDocument xDoc = XDocument.Load("file.xml");
var personNames = (from x in xDoc.Descendants("person").Descendants("name") select x).FirstOrDefault();
How to Get XML Node from XDocument
I have an xml message from a 3rd party that has a node:
<ClinicalDocument xmlns="urn:hl7-org:v3" xmlns:npfitlc="NPFIT:HL7:Localisation"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
classCode="DOCCLIN" moodCode="EVN">
I created a Namespace object to use to identify npfitlc items under this node:
ns.AddNamespace("npfitlc", "NPFIT:HL7:Localisation");
But when I try to choose the ClinicalDocument node it can't find it:
XmlNode myNode = soapEnvelop.SelectSingleNode
("//soap:Envelope/soap:Body/itk:DistributionEnvelope/itk:payloads/itk:
payload/ClinicalDocument", ns);
As you can see in my doc there are multiple nodes to get to Clinical Document. And when I reference down to itk:payload it locates it fine:
XmlNode myNode = soapEnvelop.SelectSingleNode
("//soap:Envelope/soap:Body/itk:DistributionEnvelope/itk:
payloads/itk:payload", ns);
I took out xmlns="urn:hl7-org:v3" from the ClinicalDocument tag and then I could find it find with my SelectSingleNode call, but the system I sent the message to fails validation because that is missing.
I am not sure how to handle it where there is a "root" namespace defined in that node.
ClinicalDocument has no prefix and it has an xmlns="urn:hl7-org:v3" namespace declaration, which means that its namespace is urn:hl7-org:v3. The rest of the namespace declarations there are completely irrelevant for the purpose of selecting this particular element.
So what you need to do is...
Add that namespace to your namespace manager (using any nonempty prefix):
ns.AddNamespace("hl", "urn:hl7-org:v3");
Use that prefix in your XPath:
XmlNode myNode =
soapEnvelop.SelectSingleNode("//soap:Envelope/soap:Body" +
"/itk:DistributionEnvelope/itk:payloads" +
"/itk:payload/hl:ClinicalDocument", ns);
and that should do it.
I have the following XML structure:
<?xml version="1.0" encoding="utf-16"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance
" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<StoreResponse xmlns="http://www.some-site.com">
<StoreResult>
<Message />
<Code>OK</Code>
</StoreResult>
</StoreResponse>
</soap:Body>
</soap:Envelope>
I need to get the InnerText from Codeout of this document and I need help with the appropriate XPATH statement.
I'm really confused by XML namespaces. While working on a previous namespace problem in another XML document, I learned, that even if there's nothing in front of Code (e.g. ns:Code), it is still part of a namespace defined by the xmlns attribute in its parent node. Now, there are multiple xmlns nodes defined in parents of Code. What is the namespace that I need to specify in an XPATH statement? Is there such a thing as a "primary namespace"? Do childnodes inherit the (primary) namespace of it's parents?
The namespace of the <Code> element is http://www.some-site.com. xmlsn:xxx means that names prefixed by xxx: (like soap:Body) have that namespace. xmlns by itself means that this is the default namespace for names without any prefix.
An example of using an XDocument (Linq) approach:
XNamespace ns = "http://www.some-site.com";
var document = XDocument.Parse("your-xml-string");
var elements = document.Descendants( ns + "StoreResult" )
Descendant elements will inherit the last immediate namespace. In your example you will need to create two namespaces one for the soap envelope and a second for "some-site".
Here's an option I found in this question: Weirdness with XDocument, XPath and namespaces
var xml = "<your xml>";
var doc = XDocument.Parse(xml); // Could use .Load() here too
var code = doc.XPathSelectElement("//*[local-name()='Code']");
When generating XML from XmlDocument in .NET, a blank xmlns attribute appears the first time an element without an associated namespace is inserted; how can this be prevented?
Example:
XmlDocument xml = new XmlDocument();
xml.AppendChild(xml.CreateElement("root",
"whatever:name-space-1.0"));
xml.DocumentElement.AppendChild(xml.CreateElement("loner"));
Console.WriteLine(xml.OuterXml);
Output:
<root xmlns="whatever:name-space-1.0"><loner xmlns="" /></root>
Desired Output:
<root xmlns="whatever:name-space-1.0"><loner /></root>
Is there a solution applicable to the XmlDocument code, not something that occurs after converting the document to a string with OuterXml?
My reasoning for doing this is to see if I can match the standard XML of a particular protocol using XmlDocument-generated XML. The blank xmlns attribute may not break or confuse a parser, but it's also not present in any usage that I've seen of this protocol.
Thanks to Jeremy Lew's answer and a bit more playing around, I figured out how to remove blank xmlns attributes: pass in the root node's namespace when creating any child node you want not to have a prefix on. Using a namespace without a prefix at the root means that you need to use that same namespace on child elements for them to also not have prefixes.
Fixed Code:
XmlDocument xml = new XmlDocument();
xml.AppendChild(xml.CreateElement("root", "whatever:name-space-1.0"));
xml.DocumentElement.AppendChild(xml.CreateElement("loner", "whatever:name-space-1.0"));
Console.WriteLine(xml.OuterXml);
Thanks everyone to all your answers which led me in the right direction!
This is a variant of JeniT's answer (Thank you very very much btw!)
XmlElement new_element = doc.CreateElement("Foo", doc.DocumentElement.NamespaceURI);
This eliminates having to copy or repeat the namespace everywhere.
If the <loner> element in your sample XML didn't have the xmlns default namespace declaration on it, then it would be in the whatever:name-space-1.0 namespace rather than being in no namespace. If that's what you want, you need to create the element in that namespace:
xml.CreateElement("loner", "whatever:name-space-1.0")
If you want the <loner> element to be in no namespace, then the XML that's been produced is exactly what you need, and you shouldn't worry about the xmlns attribute that's been added automatically for you.
Since root is in an unprefixed namespace, any child of root that wants to be un-namespaced has to be output like your example. The solution would be to prefix the root element like so:
<w:root xmlns:w="whatever:name-space-1.0">
<loner/>
</w:root>
code:
XmlDocument doc = new XmlDocument();
XmlElement root = doc.CreateElement( "w", "root", "whatever:name-space-1.0" );
doc.AppendChild( root );
root.AppendChild( doc.CreateElement( "loner" ) );
Console.WriteLine(doc.OuterXml);
If possible, create a serialization class then do:
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
XmlSerializer serializer = new XmlSerializer(yourType);
serializer.Serialize(xmlTextWriter, someObject, ns);
It's safer, and you can control the namespaces with attributes if you really need more control.
I've solved the problem by using the Factory Pattern. I created a factory for XElement objects. As parameter for the instantiation of the factory I've specified a XNamespace object. So, everytime a XElement is created by the factory the namespace will be added automatically. Here is the code of the factory:
internal class XElementFactory
{
private readonly XNamespace currentNs;
public XElementFactory(XNamespace ns)
{
this.currentNs = ns;
}
internal XElement CreateXElement(String name, params object[] content)
{
return new XElement(currentNs + name, content);
}
}
Yes you can prevent the XMLNS from the XmlElement .
First Creating time it is coming : like that
<trkpt lat="30.53597" lon="-97.753324" xmlns="">
<ele>249.118774</ele>
<time>2006-05-05T14:34:44Z</time>
</trkpt>
Change the code : And pass xml namespace
like this
C# code:
XmlElement bookElement = xdoc.CreateElement("trkpt", "http://www.topografix.com/GPX/1/1");
bookElement.SetAttribute("lat", "30.53597");
bookElement.SetAttribute("lon", "97.753324");