Неверное определение корневого элемента в XML-схеме при генерации XSD на лету - PullRequest
2 голосов
/ 15 марта 2019

Да, я посмотрел на этот вопрос: Неверное определение корневого элемента в схеме XML

Вот пример моего кода, который загружает XML и проверяет его по схеме XMLгенерируется на лету.

Проблема заключается в том, что при добавлении схемы XML, сгенерированной как объект документа DOM, я получаю сообщение об ошибке:

EOleException: / schema

Неверное определение корневого элемента в схеме XML

, но когда я перезагружаю документ XSD dom в себя в виде строки:

xsd.loadXML(xsd.xml);

ошибка исчезает.

Я сделал также 2 отладочных выхода XSD: до перезагрузки и после.Оба файла идентичны побайтно!

Я понятия не имею, что может быть не так, и предполагаю, что если строковые представления документов 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.

1 Ответ

1 голос
/ 18 марта 2019

Проблема заключалась в отсутствии 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.
...