Domanda

Sto cercando di convalidare un file XML rispetto agli schemi a cui fa riferimento. (Uso di Delphi e MSXML2_TLB.) Il codice (parte rilevante del) ha un aspetto simile al seguente:

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;

Questo ha il risultato che la cache è caricata ( schemas.length > 0 ), ma poi il prossimo incarico solleva un'eccezione: " è possibile utilizzare solo XMLSchemaCache-schemacollections. "

Come devo procedere?

È stato utile?

Soluzione

Ho escogitato un approccio che sembra funzionare. Prima carico lo schema in modo esplicito, quindi li aggiungo allo schema di raccolta. Successivamente carico il file xml e assegno schemacollection alla sua proprietà schemi. La soluzione ora appare così:

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;

È importante utilizzare XMLSchemaCache40 o successivo. Le versioni precedenti non seguono lo standard W3C XML Schema, ma convalidano solo contro XDR Schema, una specifica MicroSoft.

Lo svantaggio di questa soluzione è che devo caricare esplicitamente lo schema. Mi sembra che dovrebbe essere possibile recuperarli automaticamente.

Altri suggerimenti

Mentre BennyBechDk potrebbe essere sulla buona strada, ho alcuni problemi con il suo codice che correggerò di seguito:

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;

Se si desidera che il sistema sollevi solo l'eccezione, non c'è motivo di renderlo una funzione in primo luogo.

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;

Poiché validateDoc è un'interfaccia, verrà eliminata correttamente all'uscita dalla funzione / procedura, non è necessario eseguire lo smaltimento da soli. Se si chiama ValidateXmlDoc e non si ottiene un'eccezione, è valido. Personalmente mi piace la prima chiamata, IsValidXMLDoc che restituisce true se valido o false in caso contrario (e non genera eccezioni al di fuori di se stesso).

Ho lavorato sulla soluzione di Miel per risolvere il disavventura. Apro il file XML due volte, una volta per ottenere gli spazi dei nomi e l'altro, dopo aver creato la raccolta di schemi, per convalidare il file. Per me funziona. Sembra che IXMLDOMDocument2, una volta aperto, non accetta di impostare la proprietà degli schemi.

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;

Ho precedentemente convalidato documenti XML utilizzando il seguente codice:

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;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top