2

Yes, I took a look at this question: Incorrect definition for the root element in XML schema

Here is a sample of my code that loads XML and checks it against XML schema generated on the fly.

The problem is: when I add an XML schema generated as a DOM document object, I get an error:

EOleException: /schema

Incorrect definition for the root element in XML schema

but when I reload the XSD dom document into itself as a string:

xsd.loadXML(xsd.xml);

error disappears.

I made also 2 debug outputs of XSD: before reload and after. Both files are identical byte-to-byte!!!

I have no idea what could be wrong and assume that when string representations of XML documents are identical, then the objects' structures are identical too.

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.
Community
  • 1
  • 1
Paul
  • 25,812
  • 38
  • 124
  • 247

1 Answers1

1

The problem was the absence of namespaceURI for all nodes. It must be http://www.w3.org/2001/XMLSchema and it will not be set automatically for every new node.

Creating name-spaced elements with MSXML is not so easy. The amount of code triples:

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.

More friendly version:

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.
Paul
  • 25,812
  • 38
  • 124
  • 247