.NET 与 .COM 中的 XML 复杂命名空间
本文关键字:复杂 命名空间 XML 中的 COM NET | 更新日期: 2023-09-27 18:28:09
有一些德语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 classic中实现,它不直接支持.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(Microsoft XML,v6.0(将基于MSXML2的旧Navision代码转换为C#,并且我得到了相同的正确输出,而.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);
}
如果我使用相同的 URL 进行xmlns:xsi
和xsi:schemaLocation
,命名空间前缀将是正确的,但当然无法用它验证创建的文档。
使用 .Net 从 3.x 到 4.5.1 进行测试。
谁错了 - COM,.Net还是我?这是一个错误还是一个功能?
不,它不是 .Net 错误或功能。这只是代码中的一个问题。让我们看一下指定的命名空间。
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" // <----
);
你现在看到区别了吗?因此,您应该重写属性创建并提供http://www.w3.org/2001/XMLSchema-instance
作为命名空间,因为xsi
映射到它:
att = dotNetDoc.CreateAttribute(
"xsi",
"schemaLocation",
"http://www.w3.org/2001/XMLSchema-instance" // <----
);
注意。如果您使用上面的代码(使用 CreateAttribute
方法(,则可以省略手动创建xsi
声明(即 root.SetAttribute("xmlns:xsi", "...")
(。此声明将以隐式方式生成。
或者,您应该使用下一行代码:
root.SetAttribute(
"xmlns:xsi",
"http://www.w3.org/2001/XMLSchema-instance" // <----
);
root.SetAttribute(
"schemaLocation",
"http://www.w3.org/2001/XMLSchema-instance", // <----
"http://www.opentrans.org/XMLSchema/2.1 opentrans_2_1.xsd"
);
但这不是代码的唯一问题,因为您混合了解析 XML 来创建根元素和为其他元素创建 DOM 的过程。所以选择其中之一。
这是最终代码,它是 XML 表示形式:
XmlDocument document = new XmlDocument();
XmlDeclaration declaration = document.CreateXmlDeclaration("1.0", "ISO-8859-1", "yes");
document.AppendChild(declaration);
XmlElement invoice = document.CreateElement("INVOICE", "http://www.opentrans.org/XMLSchema/2.1");
document.AppendChild(invoice);
invoice.SetAttribute("version", "2.1");
invoice.SetAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
invoice.SetAttribute("schemaLocation", "http://www.w3.org/2001/XMLSchema-instance", "http://www.opentrans.org/XMLSchema/2.1 opentrans_2_1.xsd");
invoice.SetAttribute("xmlns:bmecat", "http://www.bmecat.org/bmecat/2005");
invoice.SetAttribute("xmlns:xmime", "http://www.w3.org/2005/05/xmlmime");
<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
<INVOICE version="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"
xmlns="http://www.opentrans.org/XMLSchema/2.1" />
但是,如果您使用的是 .Net 3.5 及更高版本,请使用 LINQ to XML,因为它更具可读性:
XNamespace xsi = "http://www.w3.org/2001/XMLSchema-instance";
XDocument document = new XDocument(
new XDeclaration("1.0", "ISO-8859-1", "yes"),
new XElement(
XName.Get("INVOICE", "http://www.opentrans.org/XMLSchema/2.1"),
new XAttribute("version", "2.1"),
new XAttribute(XNamespace.Xmlns + "xsi", "http://www.w3.org/2001/XMLSchema-instance"),
new XAttribute(xsi + "schemaLocation", "http://www.opentrans.org/XMLSchema/2.1 opentrans_2_1.xsd"),
new XAttribute(XNamespace.Xmlns + "bmecat", "http://www.bmecat.org/bmecat/2005"),
new XAttribute(XNamespace.Xmlns + "xmime", "http://www.w3.org/2005/05/xmlmime")
)
);
用简单的方法去做。 只需解析一个字符串 xml
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication62
{
class Program
{
static void Main(string[] args)
{
string xml =
"<?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>";
XDocument doc = XDocument.Parse(xml);
}
}
}