我正在尝试根据它引用的模式验证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。”
我应该怎么做?
答案 0 :(得分:6)
我想出了一种似乎有用的方法。我首先显式加载模式,然后将它们添加到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;
使用XMLSchemaCache40或更高版本非常重要。早期版本不遵循W3C XML Schema标准,而只是针对MicroSoft规范的XDR Schema进行验证。
此解决方案的缺点是我需要显式加载模式。在我看来,应该可以自动检索它们。
答案 1 :(得分: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(并且不会在异常之外引发异常)。
答案 2 :(得分:1)
我致力于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;
答案 3 :(得分: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;