xml delphi xsd dtd msxml

validación de esquema con msxml en delphi



xsd dtd (4)

Estoy intentando validar un archivo XML contra las referencias del esquema al que hace referencia. (Usando Delphi y MSXML2_TLB). El código (parte relevante del) se ve más o menos así:

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;

Esto tiene el resultado de que la memoria caché está cargada (schemas.length> 0), pero luego la siguiente asignación genera una excepción: "solo se pueden usar XMLSchemaCache-schemacollections".

¿Cómo debo ir sobre esto?

Gracias, Miel.


Trabajé en la solución de Miel para resolver la desventaja. Abrí el xml dos veces, una para obtener los espacios de nombres, y el otro, después de crear la colección de esquemas, para validar el archivo. Esto funciona para mi. Parece que IXMLDOMDocument2, una vez abierto, no acepta establecer la propiedad de esquemas.

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;


Si bien BennyBechDk podría estar en el camino correcto, tengo algunos problemas con su código que voy a corregir a continuación:

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 quería que el sistema simplemente planteara la excepción, entonces no hay razón para hacerlo funcionar en primer lugar.

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;

Debido a que validateDoc es una interfaz, se eliminará correctamente a medida que la función / procedimiento finalice, no hay necesidad de realizar la eliminación usted mismo. Si llama a ValidateXmlDoc y no obtiene una excepción, entonces es válido. Personalmente, me gusta la primera llamada, IsValidXMLDoc que devuelve verdadero si es válido o falso si no (y no genera excepciones fuera de sí mismo).


He encontrado un enfoque que parece funcionar. Primero cargo los esquemas explícitamente, luego agrego themn a schemacollection. A continuación, cargué el archivo xml y asigné el schemacollection a su propiedad schemas. La solución ahora se ve así:

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;

Es importante usar XMLSchemaCache40 o posterior. Las versiones anteriores no siguen el estándar W3C XML Schema, sino que solo validan contra XDR Schema, una especificación de MicroSoft.

La desventaja de esta solución es que necesito cargar los esquemas explícitamente. Me parece que debería ser posible recuperarlos automáticamente.


He validado documentos XML con el siguiente código:

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;