2009-01-15 87 views
5

我试图根据架构的引用来验证XML文件。 (使用Delphi和MSXML2_TLB)的代码(相关部分)看起来是这样的:在delphi中使用msxml进行模式验证

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; 

这有缓存加载的结果(schemas.length> 0),但随后的下一个任务将引发异常:“只能使用XMLSchemaCache-schemacollections”。

我应该怎么办?

谢谢,米尔。

回答

5

我想出了一种似乎可行的方法。我首先显式加载模式,然后将它们添加到模式集合中。接下来,我加载xml文件并将schemacollection分配给它的模式属性。现在的解决方案如下所示:

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; 

使用XMLSchemaCache40或更高版本很重要。早期版本不遵循W3C XML Schema标准,但仅针对MicroSoft规范XDR Schema进行验证。

该解决方案的缺点是我需要显式加载架构。在我看来,应该可以自动检索它们。

0

我曾尝试使用下面的代码先前验证XML文档:

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; 
1

虽然BennyBechDk可能是在正确的轨道上,我有自己的代码的一些问题,我会在下面更正:

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; 

如果您希望系统只是引发异常,那么没有理由使它成为函数。

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; 

因为validateDoc是一个接口,它会以适当方式处理作为函数/过程退出,就没有必要自己执行处置。如果您调用ValidateXmlDoc并且没有得到异常,那么它是有效的。就我个人而言,我喜欢第一个调用IsValidXMLDoc,如果有效,则返回true,否则返回false(并且不会在其自身之外引发异常)。

+0

我不能得到这个工作。 TXMLDocument出现“Undeclared identifier”错误。我是否需要导入除msxml以外的其他内容才能使其工作? – Miel 2009-01-20 12:28:00

+0

您还需要使用XMLDoc单元。 – 2009-01-26 08:27:31

1

我从事Miel的解决方案,以解决这个问题。我打开xml两次,一次获取命名空间,另一次在创建模式集合之后验证文件。这个对我有用。 似乎IXMLDOMDocument2一旦打开,就不会接受设置模式属性。

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;