【发布时间】:2015-12-26 12:46:57
【问题描述】:
发票有一些德国 xml 格式,由名为 OpenTrans 的“弗劳恩霍夫研究所”定义,这是大约 2.1 版。根据定义,此类发票文档的标题必须如下所示,包括多个命名空间:
<?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"/>
我的第一个版本 - 仍在使用 - 已在 Dynamics Nav 经典版中实现,它不直接支持 .Net。因此,这些天我不得不使用 COM 对象 MSXML2。
现在我正在尝试用 C#/.Net (4.5.1) 重写它,但其中一个命名空间出现了一些奇怪的问题。虽然 MSXML2 创建的上述根节点是正确的(特别是 xsi:schemaLocation 命名空间),但我的 .Net 代码的输出不是我想要的:
<?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 已转换为默认命名空间 d1p1:schemaLocation 并且 d1p1(当然)已添加到命名空间列表中。
为了能够比较这两种尝试,我将基于 MSXML2 的旧 Navision 代码转换为 C#,使用相同的旧 MSXML2(Microsoft XML,v6.0),我得到了相同的正确输出,而输出.Net 代码不会创建我需要获取的命名空间。
这是我的 C# 代码的两个版本:
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);
}
如果我为 xmlns:xsi 和 xsi:schemaLocation 使用相同的 URL,命名空间前缀将是正确的,但当然创建的文档不能用它来验证。
使用 .Net 从 3.x 到 4.5.1 进行测试。
谁错了 - COM、.Net 还是我?是错误还是功能?
【问题讨论】:
-
只需谷歌“d1p1 命名空间”。例如,在 this Q+A 的 cmets 中覆盖得很好。
-
没用,因为他在调用
XmlDocument.CreateAttribute时使用了错误的命名空间。 -
汉斯:感谢您的回答。我知道这有很多其他的解释,它们都有共同点,我没有找到我的问题的原因 - 至少不是 XmlDocument。通过使用命名空间管理器添加命名空间是我已经尝试过的。但没有帮助。比我发现几个谷歌线程说,命名空间管理器仅适用于 xPath,对编写 xml 没有影响。错了吗?
-
@Yoh Deadfall:我尝试了所有我能想象到的变化——在您看来,CreateAttribute 的正确参数是什么。我还尝试了使用: root.SetAttribute("xsi:schemaLocation", "opentrans.org/XMLSchema/2.1 opentrans_2_1.xsd") 导致属性 schemaLocation="..." 而不是 xsi:schemaLocation ...
-
@Pidi 我在回答中描述了问题所在。请参阅代码中的箭头。
标签: c# xml namespaces