Как добавить пространство имен в msxml DOMDocument?

Как добавить схему в 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 свойство, которое получает или устанавливает 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;

Но это не вызывает никаких xmlns быть выпущенным.

Так что теперь я сдаюсь и спрашиваю Stackru.

Вместо того, чтобы пытаться построить XML-документ правильным способом, я всегда мог бы использовать StringBuilder создать XML вручную, а затем проанализировать его в объект XML-документа.

Но я бы предпочел сделать это правильно.

1 ответ

Решение

Хитрость заключается в том, чтобы реализовать 2-й уровень W3C DOM и метод 3 createElementNS:

Создает элемент с указанным URI пространства имен и квалифицированным именем.

Синтаксис

element = document.createElementNS(namespaceURI, qualifiedName);

Однако MSXML 6 поддерживает только DOM Level 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");       

Бонус Чтение

Другие вопросы по тегам