Question

J'essaie de valider un fichier XML par rapport aux schémas qu'il référence. (Utilisation de Delphi et MSXML2_TLB.) Le code (la partie pertinente du code) ressemble à ceci:

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;

Cela a pour résultat que le cache est chargé ( schemas.length > 0 ), mais l'assignation suivante déclenche une exception: "seules les commandes XMLSchemaCache-schemacollections peuvent être utilisées."

Comment dois-je m'y prendre?

Était-ce utile?

La solution

J'ai mis au point une approche qui semble fonctionner. Je commence par charger explicitement le schéma, puis je les ajoute à la collection schem. Ensuite, je charge le fichier XML et assigne la schemacollection à sa propriété schemas. La solution ressemble maintenant à ceci:

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 := xml.load(xmlFile);
    if not Result then
      err := xml.parseError
    else
      err := nil;
end;

Il est important d’utiliser XMLSchemaCache40 ou une version ultérieure. Les versions précédentes ne respectent pas le standard XML Schema du W3C, elles ne valident que par rapport à XDR Schema, une spécification MicroSoft.

L'inconvénient de cette solution est que je dois charger explicitement le schéma. Il me semble qu’il devrait être possible de les récupérer automatiquement.

Autres conseils

Bien que BennyBechDk soit peut-être sur la bonne voie, son code me pose quelques problèmes que je vais corriger ci-dessous:

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;

Si vous souhaitez que le système lève simplement l'exception, il n'y a aucune raison de le faire en premier lieu.

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;

Etant donné que validateDoc est une interface, elle sera éliminée correctement à la sortie de la fonction / de la procédure. Il n’est donc pas nécessaire de procéder à la destruction vous-même. Si vous appelez ValidateXmlDoc sans obtenir une exception, celle-ci est valide. Personnellement, j'aime bien le premier appel, IsValidXMLDoc, qui renvoie true si valide ou false sinon (et ne génère pas d'exceptions en dehors de lui-même).

J'ai travaillé sur la solution de Miel pour résoudre le problème. J'ouvre le xml deux fois, une fois pour obtenir les espaces de noms, et l'autre, après avoir créé la collection de schémas, pour valider le fichier. Ça marche pour moi. Il semble que IXMLDOMDocument2, une fois ouvert, n’accepte pas de définir la propriété schemas.

function TForm1.ValidXML2(const xmlFile: String;
  out err: IXMLDOMParseError): Boolean;
var
  xml, xml2, xsd: IXMLDOMDocument2;
  schemas, cache: IXMLDOMSchemaCollection;
begin
  xml := CoDOMDocument.Create;
  if xml.load(xmlFile) then
    begin
    schemas := xml.namespaces;
    if schemas.length > 0 then
      begin
      xsd := CoDOMDocument40.Create;
      xsd.Async := False;
      xsd.load(schemas.namespaceURI[0]);
      cache := CoXMLSchemaCache40.Create;
      cache.add(schemas.namespaceURI[1], xsd);
      xml2 := CoDOMDocument40.Create;
      xml2.async := False;
      xml2.schemas := cache;
      Result := xml2.load(xmlFile);
      //err := xml.validate;
      if not Result then
        err := xml2.parseError
      else
        err := nil;
      end;
    end;

J'ai déjà validé des documents XML à l'aide du code suivant:

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;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top