проверка схемы с помощью msxml в delphi - PullRequest
7 голосов
/ 15 января 2009

Я пытаюсь проверить 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.»

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

Ответы [ 4 ]

6 голосов
/ 19 февраля 2009

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

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

1 голос
/ 14 декабря 2011

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

Хотя 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 голосов
/ 16 января 2009

Ранее я проверял 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;
...