在delphi中使用msxml进行模式验证

时间:2022-09-07 17:18:03

I'm trying to validate an XML file against the schemas it references. (Using Delphi and MSXML2_TLB.) The (relevant part of the) code looks something like this:

我正在尝试根据它引用的模式验证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;

This has the result that cache is loaded (schemas.length > 0), but then the next assignment raises an exception: "only XMLSchemaCache-schemacollections can be used."

这导致加载缓存(schemas.length> 0),但是下一个赋值会引发异常:“只能使用XMLSchemaCache-schemacollections。”

How should I go about this?

我该怎么办呢?

4 个解决方案

#1


5  

I've come up with an approach that seems to work. I first load the schema's explicitly, then add themn to the schemacollection. Next I load the xml-file and assign the schemacollection to its schemas property. The solution now looks like this:

我想出了一种似乎有用的方法。我首先显式加载模式,然后将它们添加到schemacollection。接下来,我加载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;

It is important to use XMLSchemaCache40 or later. Earlier versions don't follow the W3C XML Schema standard, but only validate against XDR Schema, a MicroSoft specification.

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

The disadvantage of this solution is that I need to load the schema's explicitly. It seems to me that it should be possible to retrieve them automatically.

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

#2


1  

While BennyBechDk might be on the right track, I have a few problems with his code that I'm going to correct below:

虽然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;

If you wanted the system to just raise the exception, then there is no reason to make it a function in the first place.

如果您希望系统只是引发异常,那么就没有理由将它作为一个函数。

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;

Because validateDoc is an interface, it will be disposed of properly as the function/procedure exits, there is no need to perform the disposal yourself. If you call ValidateXmlDoc and don't get an exception then it is valid. Personally I like the first call, IsValidXMLDoc which returns true if valid or false if not (and does not raise exceptions outside of itself).

因为validateDoc是一个接口,所以当函数/过程退出时它将被正确处理,不需要自己进行处理。如果您调用ValidateXmlDoc并且没有获得异常,那么它是有效的。我个人喜欢第一个调用,IsValidXMLDoc如果有效则返回true,否则返回false(并且不会在异常之外引发异常)。

#3


1  

I worked on the Miel´s solution to solve the disadventage. I open the xml twice, once to get the namespaces, and the other, after create the schema collection, to validate the file. It works for me. It seems like the IXMLDOMDocument2, once open, don´t accepts set the schemas property.

我致力于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


0  

I have previously validated XML documents using the following code:

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


5  

I've come up with an approach that seems to work. I first load the schema's explicitly, then add themn to the schemacollection. Next I load the xml-file and assign the schemacollection to its schemas property. The solution now looks like this:

我想出了一种似乎有用的方法。我首先显式加载模式,然后将它们添加到schemacollection。接下来,我加载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;

It is important to use XMLSchemaCache40 or later. Earlier versions don't follow the W3C XML Schema standard, but only validate against XDR Schema, a MicroSoft specification.

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

The disadvantage of this solution is that I need to load the schema's explicitly. It seems to me that it should be possible to retrieve them automatically.

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

#2


1  

While BennyBechDk might be on the right track, I have a few problems with his code that I'm going to correct below:

虽然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;

If you wanted the system to just raise the exception, then there is no reason to make it a function in the first place.

如果您希望系统只是引发异常,那么就没有理由将它作为一个函数。

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;

Because validateDoc is an interface, it will be disposed of properly as the function/procedure exits, there is no need to perform the disposal yourself. If you call ValidateXmlDoc and don't get an exception then it is valid. Personally I like the first call, IsValidXMLDoc which returns true if valid or false if not (and does not raise exceptions outside of itself).

因为validateDoc是一个接口,所以当函数/过程退出时它将被正确处理,不需要自己进行处理。如果您调用ValidateXmlDoc并且没有获得异常,那么它是有效的。我个人喜欢第一个调用,IsValidXMLDoc如果有效则返回true,否则返回false(并且不会在异常之外引发异常)。

#3


1  

I worked on the Miel´s solution to solve the disadventage. I open the xml twice, once to get the namespaces, and the other, after create the schema collection, to validate the file. It works for me. It seems like the IXMLDOMDocument2, once open, don´t accepts set the schemas property.

我致力于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


0  

I have previously validated XML documents using the following code:

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

相关文章