4

如何将架构添加到IXMLDOMDocument?

例如,我想生成 XML:

<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
   <Relationship Id="rId1" Type="Frob" Target="Grob"/>
</Relationships>

我可以构造 DOMDocument60 对象(伪代码)

DOMDocument60 doc = new DOMDocument60();

IXMLDOMElement relationships = doc.appendChild(doc.createElement("Relationships"));

IXMLDOMElement relationship = relationships.appendChild(doc.createElement("Relationship"));
   relationship.setAttribute("Id", "rId1");
   relationship.setAttribute("Type", "Frob");
   relationship.setAttribute("Target", "Grob");

现在是如何添加命名空间的问题。

如何添加命名空间?

如果我采取明显的解决方案,请在关系节点上设置一个名为xmlns

<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">

通过类似的东西:

relationships.setAttribute("xmlns", 
      "http://schemas.openxmlformats.org/package/2006/relationships");

保存文档时,会导致生成的 xml 错误:

<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
   <Relationship Id="rId1" Type="Frob" Target="Grob" xmlns=""/>
</Relationships>

它将空xmlns属性放置在每个其他元素上。在这个小测试文档中,它只错误地应用了xmlns一个元素。在现实世界中,有几十个或几百万个具有空xmlns属性的其他元素。

namespaceURI 属性

我尝试设置元素的namespaceURI属性:Relationships

relationshps.namespaceURI := "http://schemas.openxmlformats.org/package/2006/relationships"; 

但该属性是只读的

schemas 属性

文档确实有一个schemas属性,它获取或设置一个XMLSchemaCache对象。但它需要一个实际的模式文档。例如,试图只设置一个模式是行不通的:

schemas = new XMLSchemaCache60();
schemas.add('', 'http://schemas.openxmlformats.org/spreadsheetml/2006/main');
doc.schemas := schemas;

但这会尝试实际加载架构 url,而不是不加载架构,因为它不是 URI。

也许我必须随机尝试其他事情:

schemas = new XMLSchemaCache60();
schemas.add('http://schemas.openxmlformats.org/spreadsheetml/2006/main', null);
doc.schemas := schemas;

但这会导致 noxmlns被发射。

与其尝试以正确的方式构建 XML 文档,我总是可以使用 aStringBuilder手动构建 XML,然后将其解析为 XML Document 对象。

但我宁愿以正确的方式去做。

4

1 回答 1

6

诀窍是实现 W3C DOM Level 2 和 3 的方法createElementNS

创建具有指定命名空间 URI 和限定名称的元素。

句法

element = document.createElementNS(namespaceURI, qualifiedName);

但是 MSXML 6 仅支持 DOM 级别 1。

幸运的是,W3C DOM Level 1 确实有一个方法来创建一个带有命名空间的元素:createNode

使用提供的类型、名称和命名空间创建节点。

HRESULT createNode(VARIANT Type, BSTR name, BSTR namespaceURI, out IXMLDOMNode node);

因此我的解决方案是我必须改变:

relationships: IXMLDOMElement = doc.createElement("Relationships"); 

进入:

const NODE_ELEMENT: Integer = 1;
const ns: string = "http://schemas.openxmlformats.org/package/2006/relationships";

relationships: IXMLDOMElement = doc.createNode(NODE_ELEMENT, "Relationships", namespace); 

一个糟糕的部分是必须在该命名空间中创建每个元素:

function AddElementNS(IXMLDOMNode parentNode, String tagName, String namespaceURI): IXMLDOMElement;
{
   doc: IXMLDOMDocument = parentNode as IXMLDOMDocument;
   if (doc == null) 
      doc = parentNode.ownerDocument;

   if (namespaceURI <> "")
      Result = doc.createNode(NODE_ELEMENT, tagName, namespaceURI)
   else
      Result = doc.createElement(tagName);

   parentNode.appendChild(Result);
}

relationships: IXMLDOMElement = AddElementNS(doc, "Relationships", ns);

relationship: IXMLDOMElement = AddElementNS(relationships, "Relationship", ns);
   relationship.setAttribute("Id", "rId1");
   relationship.setAttribute("Type", "Frob");
   relationship.setAttribute("Target", "Grob");       

奖金阅读

于 2016-03-17T13:58:27.403 回答