views:

2662

answers:

4

Hi,

I'm trying to validate an XML file against the schema's it references. (Using Delphi and MSXML2_TLB.) The (relevant part of the) code looks something like this:

procedure TfrmMain.ValidateXMLFile;
var
    xml: IXMLDOMDocument2;
    err: IXMLDOMParseError;
    schemas: IXMLDOMSchemaCollection;
begin
    xml := ComsDOMDocument.Create;
    if xml.load('Data/file.xml') then
    begin
        schemas := xml.namespaces;
        if schemas.length > 0 then
        begin
            xml.schemas := schemas;
            err := xml.validate;
        end;
    end;
end;

This has the result that cache is loaded (schemas.length > 0), but then the next assignment raises an exception: "only XMLSchemaCache-schemacollections can be used."

How should I go about this?

Thanks, Miel.

A: 

I have previosly validated usen the following code:

uses Classes, XMLIntf, SysUtils;

function ValidateXMLDoc(aXmlDoc: IXMLDocument): boolean;
var
  validateDoc: IXMLDocument;
begin
  validateDoc := TXMLDocument.Create(nil);

  validateDoc.ParseOptions := [poResolveExternals, poValidateOnParse];
  validateDoc.XML := aXmlDoc.XML;

  validateDoc.Active := true;
  Result := True;
end;
BennyBechDk
A: 

While BennyBechDk might be on the right track, I have a few problems with his code that I'm going to correct below:

uses Classes, XMLIntf, xmlDoc, SysUtils;

function IsValidXMLDoc(aXmlDoc: IXMLDocument): boolean;
var
  validateDoc: IXMLDocument;
begin
  result := false;  // eliminate any sense of doubt, it starts false period.
  validateDoc := TXMLDocument.Create(nil);
  try   
    validateDoc.ParseOptions := [poResolveExternals, poValidateOnParse];
    validateDoc.XML := aXmlDoc.XML;
    validateDoc.Active := true;
    Result := True;
  except
    // for this example, I am going to eat the exception, normally this
    // exception should be handled and the message saved to display to 
    // the user.
  end;
end;

If you wanted the system to just raise the exception, then there is no reason to make it a function in the first place.

uses Classes, XMLIntf, XMLDoc, SysUtils;

procedure ValidateXMLDoc(aXmlDoc: IXMLDocument);
var
  validateDoc: IXMLDocument;
begin
  validateDoc := TXMLDocument.Create(nil);
  validateDoc.ParseOptions := [poResolveExternals, poValidateOnParse];
  validateDoc.XML := aXmlDoc.XML;
  validateDoc.Active := true;
end;

Because validateDoc is an interface, it will be disposed of properly as the function/procedure exits, there is no need to perform the disposal yourself. If you call ValidateXmlDoc and don't get an exception then it is valid. Personally I like the first call, IsValidXMLDoc which returns true if valid or false if not (and does not raise exceptions outside of itself).

skamradt
I can't get this to work. I get an "Undeclared identifier" error for TXMLDocument. Do I need to import something other than msxml to get this to work?
Miel
You need to use the XMLDoc unit aswell.
The_Fox
+3  A: 

I've come up with an approach that seems to work. I first load the schema's explicitly, then add themn to the schemacollection. Next I load the xml-file and assign the schemacollection to its schemas property. The solution now looks like this:

uses MSXML2_TLB  
That is:  
// Type Lib: C:\Windows\system32\msxml4.dll  
// LIBID: {F5078F18-C551-11D3-89B9-0000F81FE221}

function TfrmMain.ValidXML(
    const xmlFile: String; 
    out err: IXMLDOMParseError): Boolean;
var
    xml, xsd: IXMLDOMDocument2;
    cache: IXMLDOMSchemaCollection;
begin
    xsd := CoDOMDocument40.Create;
    xsd.Async := False;
    xsd.load('http://the.uri.com/schemalocation/schema.xsd');

    cache := CoXMLSchemaCache40.Create;
    cache.add('http://the.uri.com/schemalocation', xsd);

    xml := CoDOMDocument40.Create;
    xml.async := False;
    xml.schemas := cache;

    Result := xmlDoc.load(xmlFile);
    if not Result then
      err := xmlDoc.parseError
    else
      err := nil;
end;

It is important to use XMLSchemaCache40 or later. Earlier versions don't follow the W3C XML Schema standard, but only validate against XDR Schema, a MicroSoft specification.

The disadvantage of this solution is that I need to load the schema's explicitly. It seems to me that it should be possible to retrieve them automatically.

Miel
A: 

I have question related to below quoted text , that is what if I have to validate XML by XSD file ? what I understand is below code is just for validating the XML complete formation , ensuring that file is not corrupted.

function ValidateXMLDoc(aXmlDoc: IXMLDocument): boolean; var
validateDoc: IXMLDocument; begin
validateDoc := TXMLDocument.Create(nil); validateDoc.ParseOptions := [poResolveExternals, poValidateOnParse]; validateDoc.XML := aXmlDoc.XML; validateDoc.Active := true; Result := True; end;

Pranita J