Вопрос

Я пытаюсь проверить файл 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 ), но затем следующее назначение вызывает исключение: " можно использовать только XMLSchemaCache-schemacollections. "

Как мне поступить об этом?

Это было полезно?

Решение

Я предложил подход, который, кажется, работает. Сначала я загружаю схему явно, затем добавляю их в коллекцию схем. Затем я загружаю 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 или более позднюю версию. Более ранние версии не следуют стандарту XML-схемы W3C, а проверяются только по схеме XDR, спецификации MicroSoft.

Недостатком этого решения является то, что мне нужно явно загрузить схему. Мне кажется, что их можно было бы получить автоматически.

Другие советы

Хотя 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, если нет (и не вызывает исключений вне себя).

Я работал над решением Миэль, чтобы решить проблему. Я открываю 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;

Ранее я проверил документы 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;
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top