动态生成 XSD 时,XML 架构中的根元素定义不正确

Incorrect definition for the root element in XML schema when generating XSD on the fly

是的,我看了一下这个问题:Incorrect definition for the root element in XML schema

这是我的代码示例,它加载 XML 并根据动态生成的 XML 模式对其进行检查。

问题是:当我添加作为 DOM 文档对象生成的 XML 架构时,出现错误:

EOleException: /schema

Incorrect definition for the root element in XML schema

但是当我将 XSD dom 文档作为字符串重新加载到自身时:

xsd.loadXML(xsd.xml);

错误消失。

我还制作了 XSD 的 2 个调试输出:重新加载之前和之后。两个文件的字节到字节完全相同!!!

我不知道哪里出了问题,并假设当 XML 文档的字符串表示相同时,对象的结构也相同。

program XsdValidatorMCV;

uses
  Winapi.MSXMLIntf, System.Win.ComObj, Winapi.ActiveX;

var
  xsd: IXMLDOMDocument2;
  xsdl: IXMLDOMSchemaCollection;
  root: IXMLDOMElement;
  el: IXMLDOMElement;

begin
  CoInitialize(nil);
  xsd := CreateOleObject('Msxml2.DOMDocument.6.0') as IXMLDOMDocument2;
  xsdl := CreateOleObject('Msxml2.XMLSchemaCache.6.0') as IXMLDOMSchemaCollection;
  try
    xsd.appendChild(xsd.createProcessingInstruction('xml', 'version="1.0"'));
    root := xsd.createElement('xs:schema');
    root.setAttribute('xmlns:xs', 'http://www.w3.org/2001/XMLSchema');
    xsd.appendChild(root);
    el := xsd.createElement('xs:element');
    root.appendChild(el);
    el.setAttribute('name', 'data');

    xsd.save('generated1.xsd'); //Debug output
    //Workaround: reloading itself as string eliminates strange schema error:
    //EOleException: /schema Incorrect definition for the root element in XML schema.
    xsd.loadXML(xsd.xml);
    xsd.save('generated2.xsd'); //Debug output

    xsdl.add('', xsd); //Here is an error when without xsd.loadXML(xsd.xml)
  finally
    xsdl := nil;
    xsd := nil;
  end;
end.

问题是所有节点都缺少 namespaceURI。它必须是http://www.w3.org/2001/XMLSchema并且不会为每个新节点自动设置。

使用 MSXML 创建名称空间元素并不容易。代码量翻三倍:

const
  NODE_ELEMENT = 1;
var
  xsd: IXMLDOMDocument2;
  xsdl: IXMLDOMSchemaCollection;
  root: IXMLDOMNode;
  el: IXMLDOMNode;
  att: IXMLDOMAttribute;
begin
  CoInitialize(nil);
  xsd := CreateOleObject('Msxml2.DOMDocument.6.0') as IXMLDOMDocument2;
  xsdl := CreateOleObject('Msxml2.XMLSchemaCache.6.0') as IXMLDOMSchemaCollection;

  xsd.appendChild(xsd.createProcessingInstruction('xml', 'version="1.0"'));

  root := xsd.createNode(NODE_ELEMENT, 'xs:schema', 'http://www.w3.org/2001/XMLSchema');
  xsd.appendChild(root);

  att := xsd.createAttribute('xmlns:xs');
  att.value := 'http://www.w3.org/2001/XMLSchema';
  root.attributes.setNamedItem(att);


  el := xsd.createNode(NODE_ELEMENT, 'xs:element', 'http://www.w3.org/2001/XMLSchema');
  root.appendChild(el);

  att := xsd.createAttribute('name');
  att.value := 'data';
  el.attributes.setNamedItem(att);

  xsdl.add('', xsd);
end.

更友好的版本:

const
  XS_URI = 'http://www.w3.org/2001/XMLSchema';

function createSchemaNode(const parentNode: IXMLDOMNode; const name: WideString): IXMLDOMNode;
const
  NODE_ELEMENT = 1;
var
  doc: IXMLDOMDocument;
begin
  if Supports(parentNode, IXMLDOMDocument) then
    doc := parentNode as IXMLDOMDocument
  else
    doc := parentNode.ownerDocument as IXMLDOMDocument;
  Result := doc.createNode(NODE_ELEMENT, 'xs:' + name, XS_URI);
  parentNode.appendChild(Result);
end;

procedure setAttribute(const node: IXMLDOMNode; const name: WideString; value: OleVariant);
var
  att: IXMLDOMAttribute;
  doc: IXMLDOMDocument2;
begin
  doc := node.ownerDocument as IXMLDOMDocument2;
  att := doc.createAttribute(name);
  att.value := value;
  node.attributes.setNamedItem(att);
end;

var
  xsd: IXMLDOMDocument2;
  xsdl: IXMLDOMSchemaCollection;
  root: IXMLDOMNode;
  el: IXMLDOMNode;
begin
  CoInitialize(nil);
  xsd := CreateOleObject('Msxml2.DOMDocument.6.0') as IXMLDOMDocument2;
  xsdl := CreateOleObject('Msxml2.XMLSchemaCache.6.0') as IXMLDOMSchemaCollection;

  xsd.appendChild(xsd.createProcessingInstruction('xml', 'version="1.0"'));

  root := createSchemaNode(xsd, 'schema');
  setAttribute(root, 'xmlns:xs', XS_URI);

  el := createSchemaNode(root, 'element');
  setAttribute(el, 'name', 'data');

  xsdl.add('', xsd);
end.