There is some german xml format for invoices, defined by the "Fraunhofer Institute" called OpenTrans, an this is about version 2.1 of that. By definition the header for such an invoice document has to look like this, including multiple namespaces:
<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
<INVOICE version="2.1" xmlns="http://www.opentrans.org/XMLSchema/2.1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opentrans.org/XMLSchema/2.1 opentrans_2_1.xsd"
xmlns:bmecat="http://www.bmecat.org/bmecat/2005"
xmlns:xmime="http://www.w3.org/2005/05/xmlmime"/>
My first version of that - still in use - has been implemented within Dynamics Nav classic, which doesn't support .Net directly. Due to that I had to use the COM object MSXML2 back these days.
Now I'm trying to rewrite this in C# / .Net (4.5.1), and I'm getting some weired problem with one of the namespaces. While the above root node created by MSXML2 is correct (specificially the xsi:schemaLocation namespace) the output of my .Net code is not what I intended:
<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
<INVOICE version="2.1" xmlns="http://www.opentrans.org/XMLSchema/2.1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
d1p1:schemaLocation="http://www.opentrans.org/XMLSchema/2.1 opentrans_2_1.xsd"
xmlns:bmecat="http://www.bmecat.org/bmecat/2005"
xmlns:xmime="http://www.w3.org/2005/05/xmlmime"
xmlns:d1p1="http://www.opentrans.org/XMLSchema/2.1">
</INVOICE>
xsi:schemaLocation has been converted to a default namespace d1p1:schemaLocation and d1p1 (of course) has been added to the list of namespaces.
To be able to compare both attempts, I converted my old Navision code based on MSXML2 to C#, using the same old MSXML2 (Microsoft XML, v6.0) and I'm getting the same CORRECT output, while the output of the .Net code doesn't create the namespaces I need to get.
Here's are both versions of my C# code:
if (mode == "com")
{
MSXML2.DOMDocument60 comDoc = new MSXML2.DOMDocument60();
MSXML2.IXMLDOMProcessingInstruction xmlProcessingInst = comDoc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"ISO-8859-1\" standalone=\"yes\"");
comDoc.appendChild(xmlProcessingInst);
MSXML2.IXMLDOMNode RootNode;
MSXML2.IXMLDOMElement NewChildNode = comDoc.createElement("INVOICE");
RootNode = comDoc.appendChild(NewChildNode);
MSXML2.IXMLDOMAttribute XMLNewAttributeNode = RootNode.ownerDocument.createAttribute("version");
XMLNewAttributeNode.nodeValue = "2.1";
RootNode.attributes.setNamedItem(XMLNewAttributeNode);
XMLNewAttributeNode = RootNode.ownerDocument.createAttribute("xmlns");
XMLNewAttributeNode.nodeValue = "http://www.opentrans.org/XMLSchema/2.1";
RootNode.attributes.setNamedItem(XMLNewAttributeNode);
XMLNewAttributeNode = RootNode.ownerDocument.createAttribute("xmlns:xsi");
XMLNewAttributeNode.nodeValue = "http://www.w3.org/2001/XMLSchema-instance";
RootNode.attributes.setNamedItem(XMLNewAttributeNode);
XMLNewAttributeNode = RootNode.ownerDocument.createAttribute("xsi:schemaLocation");
XMLNewAttributeNode.nodeValue = "http://www.opentrans.org/XMLSchema/2.1 opentrans_2_1.xsd";
RootNode.attributes.setNamedItem(XMLNewAttributeNode);
// the same code for "xmlns:bmecat" attribute;
// the same code for "xmlns:xmime" attribute;
comDoc.save(@"D:\testInvoice.xml");
}
else
{
XmlDocument dotNetDoc = new XmlDocument();
dotNetDoc.LoadXml("<INVOICE></INVOICE>");
XmlElement root = dotNetDoc.DocumentElement;
XmlDeclaration xmlDeclaration = dotNetDoc.CreateXmlDeclaration("1.0", "ISO-8859-1", "yes");
dotNetDoc.InsertBefore(xmlDeclaration, root);
root.SetAttribute("version", "2.1");
root.SetAttribute("xmlns", "http://www.opentrans.org/XMLSchema/2.1");
root.SetAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
XmlAttribute att;
att = dotNetDoc.CreateAttribute("xsi", "schemaLocation", "http://www.opentrans.org/XMLSchema/2.1");
att.Value = "http://www.opentrans.org/XMLSchema/2.1 opentrans_2_1.xsd";
root.SetAttributeNode(att);
root.SetAttribute("xmlns:bmecat", "http://www.bmecat.org/bmecat/2005");
root.SetAttribute("xmlns:xmime", "http://www.w3.org/2005/05/xmlmime");
dotNetDoc.AppendChild(root);
File.WriteAllText(@"\\mbps02\Verwaltung\EDI\openTrans\2_1\testInvoice.xml", dotNetDoc.OuterXml);
}
The namespace prefixes will be correct, if I use the same URL for xmlns:xsi and xsi:schemaLocation, but of course the created document can not be validated with that.
Tested with .Net from 3.x to 4.5.1.
Who's wrong - COM, .Net or me? Is it a bug or is it a feature?
XmlDocument.CreateAttribute.