【问题标题】:schema validation with msxml in delphi在 delphi 中使用 msxml 进行架构验证
【发布时间】:2009-01-15 13:01:37
【问题描述】:

我正在尝试根据它引用的模式验证 XML 文件。 (使用 Delphi 和 MSXML2_TLB。)(相关部分)代码如下所示:

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),但接下来的赋值引发了异常:“only XMLSchemaCache-schemacollections can be used.”

我该怎么办?

【问题讨论】:

    标签: xml delphi xsd dtd msxml


    【解决方案1】:

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

    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 进行验证。

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

    【讨论】:

    • 对不起,我认为应该是 xml,而不是 xmlDoc。只是为了确保我会在编辑之前进行检查。
    【解决方案2】:

    虽然 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(并且不会在自身之外引发异常)。

    【讨论】:

    • 我无法让它工作。我收到 TXMLDocument 的“未声明的标识符”错误。我是否需要导入 msxml 以外的其他内容才能使其正常工作?
    • 这根本不会根据 XSD 模式验证 XML 文档。它不会抛出任何异常或任何东西,即使是像 <xml /> 这样的 xml 内容。
    【解决方案3】:

    我研究了 Miel 的解决方案来解决缺点。我打开 xml 两次,一次是为了获取命名空间,另一次是在创建架构集合后验证文件。这个对我有用。 似乎 IXMLDOMDocument2,一旦打开,不接受设置 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;
    

    【讨论】:

      【解决方案4】:

      我之前使用以下代码验证了 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;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-02-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-09
        • 1970-01-01
        相关资源
        最近更新 更多