TXMLDocument
不直接支持在使用MSXML时启用XSD验证,因此MSXML有责任对其进行管理。启用poResolveExternals
和poValidateOnParse
标志对此很重要,但还有其他一些因素需要考虑。最重要的是,尽管MSXML不支持引用来自XML内的XSD,但对是否在加载XML引用的XSD将实际被使用的一些限制:
Referencing XSD Schemas in Documents
要引用一个XML Schema( XSD)架构从MSXML 6.0中的XML文档,您可以使用以下任何一种方法将架构链接到XML文档,以便MSXML将使用该架构来验证文档内容。
...
的xsi:schemaLocation属性效果很好在命名空间前缀显式声明的要验证XML文档中使用的情况。
以下示例显示引用外部XSD模式MyData.xsd的XML文档,用于验证映射到“MyData:”名称空间前缀的'urn:MyData'名称空间URI中的节点。
<catalog xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xsi:schemaLocation="urn:MyData http://www.example.com/MyData.xsd"
<MyData:book xmlns:MyData="urn:MyData">
<MyData:title>Presenting XML</MyData:title>
<MyData:author>Richard Light</MyData:author>
</MyData:book>
为了使MyData的。XSD文件与配对,并使用您验证的元素和属性,与开始节点“迈德特”,该模式需要使用并包含以下架构属性:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:MyData="urn:MyData"
targetNamespace="urn:MyData"
elementFormDefault="qualified">
这些属性声明“瓮: MyData'命名空间URI和“MyData:”命名空间前缀,以便它们与在XML文件中进行这些声明的方式相同。 如果它们不匹配,则在验证期间永远不会调用指定位置的模式。
您还没有显示您的XSD,但是您显示的XML不符合上述文档中提到的规则。特别是,您错过了使用urn
命名空间映射以及您想要验证的XML节点上的前缀。某些版本的MSXML可能比其他版本更好地处理此问题,这可以解释为什么验证适用于某些机器,并且在其他机器上被忽略,具体取决于安装的MSXML版本。
话虽这么说,你可能不得不求助于文档中提到的第二种方法:
- XSD架构文件添加到架构缓存,然后高速缓存连接到DOM文档或SAX读取器,然后加载或解析XML文档。
这需要直接使用MSXML,你不能TXMLDocument
做到这一点:
MSXML还提供了连接和使用模式缓存来存储,负载和架构连接的手段一个XML文档,如下面的VBScript代码摘录:
'Create the schema cache and add the XSD schema to it.
set oSC = CreateObject("MSXML2.XMLSchemaCache.6.0")
oSC.Add "urn:MyData", "http://www.example.com/MyData.xsd"
'Create the DOM document assign the cache to its schemas property.
set oXD = CreateObject("MSXML2.DOMDocument.6.0")
oXD.schemas = oSC
'Set properties, load and validate it in the XML DOM.
的疑难杂症是,你必须知道在哪里XSD是LOCA以便将其连接到解析器。因此,您只需加载一次XML就可以提取XSD位置,然后将XSD加载到模式缓存中,然后使用附加的XSD重新加载XML。下面是一些Delphi例子:
schema validation with msxml in delphi
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;
end;
How to validate a IXMLDocument against a XML Schema?
unit XMLValidate;
// Requirements ----------------------------------------------------------------
//
// MSXML 4.0 Service Pack 1
// http://www.microsoft.com/downloads/release.asp?releaseid=37176
//
// -----------------------------------------------------------------------------
interface
uses
SysUtils, XMLIntf, xmldom, XMLSchema;
type
EValidateXMLError = class(Exception)
private
FErrorCode: Integer;
FReason: string;
public
constructor Create(AErrorCode: Integer; const AReason: string);
property ErrorCode: Integer read FErrorCode;
property Reason: string read FReason;
end;
procedure ValidateXMLDoc(const Doc: IDOMDocument; const SchemaLocation, SchemaNS: WideString); overload;
procedure ValidateXMLDoc(const Doc: XMLIntf.IXMLDocument; const SchemaLocation, SchemaNS: WideString); overload;
procedure ValidateXMLDoc(const Doc: IDOMDocument; const Schema: IXMLSchemaDoc); overload;
procedure ValidateXMLDoc(const Doc: XMLIntf.IXMLDocument; const Schema: IXMLSchemaDoc); overload;
implementation
uses
Windows, ComObj, msxmldom, MSXML2_TLB;
resourcestring
RsValidateError = 'Validate XML Error (%.8x), Reason: %s';
{ EValidateXMLError }
constructor EValidateXMLError.Create(AErrorCode: Integer; const AReason: string);
begin
inherited CreateResFmt(@RsValidateError, [AErrorCode, AReason]);
FErrorCode := AErrorCode;
FReason := AReason;
end;
{ Utility routines }
function DOMToMSDom(const Doc: IDOMDocument): IXMLDOMDocument2;
begin
Result := ((Doc as IXMLDOMNodeRef).GetXMLDOMNode as IXMLDOMDocument2);
end;
function LoadMSDom(const FileName: WideString): IXMLDOMDocument2;
begin
Result := CoDOMDocument40.Create;
Result.async := False;
Result.resolveExternals := True; //False;
Result.validateOnParse := True;
Result.load(FileName);
end;
{ Validate }
procedure InternalValidateXMLDoc(const Doc: IDOMDocument; const SchemaDoc: IXMLDOMDocument2; const SchemaNS: WideString);
var
MsxmlDoc: IXMLDOMDocument2;
SchemaCache: IXMLDOMSchemaCollection;
Error: IXMLDOMParseError;
begin
MsxmlDoc := DOMToMSDom(Doc);
SchemaCache := CoXMLSchemaCache40.Create;
SchemaCache.add(SchemaNS, SchemaDoc);
MsxmlDoc.schemas := SchemaCache;
Error := MsxmlDoc.validate;
if Error.errorCode <> S_OK then
raise EValidateXMLError.Create(Error.errorCode, Error.reason);
end;
procedure ValidateXMLDoc(const Doc: IDOMDocument; const SchemaLocation, SchemaNS: WideString);
begin
InternalValidateXMLDoc(Doc, LoadMSDom(SchemaLocation), SchemaNS);
end;
procedure ValidateXMLDoc(const Doc: XMLIntf.IXMLDocument; const SchemaLocation, SchemaNS: WideString);
begin
InternalValidateXMLDoc(Doc.DOMDocument, LoadMSDom(SchemaLocation), SchemaNS);
end;
procedure ValidateXMLDoc(const Doc: IDOMDocument; const Schema: IXMLSchemaDoc);
begin
InternalValidateXMLDoc(Doc, DOMToMSDom(Schema.DOMDocument), '');
end;
procedure ValidateXMLDoc(const Doc: XMLIntf.IXMLDocument; const Schema: IXMLSchemaDoc);
begin
InternalValidateXMLDoc(Doc.DOMDocument, DOMToMSDom(Schema.DOMDocument), '');
end;
end.
Doc := LoadXMLData(XmlFileEdit.Lines.Text);
ValidateXMLDoc(Doc, FSchemaFileName, 'http://www.foo.com');
XML Documents, Schemas and Validation
var
XML, XSDL: Variant;
begin
XSDL := CreateOLEObject('MSXML2.XMLSchemaCache.4.0');
XSDL.validateOnLoad := True;
XSDL.add('','MySchema.xsd'); // 1st argument is target namespace
ShowMessage('Schema Loaded');
XML := CreateOLEObject('MSXML2.DOMDocument.4.0');
XML.validateOnParse := True;
XML.resolveExternals := True;
XML.schemas := XSDL;
XML.load('file.xml');
ShowMessage(XML.parseError.reason);
end.
你期待它抛出什么异常,你为什么期待它?你有没有尝试捕获'Exception'而不是'EDOMParseError'?你能否展示一个不会失败的例子,并期望它失败?另外,是什么类型的XMLDoc声明为TXMLDocument或IXMLDocument?您是否知道在创建具有'nil'所有者的'TXMLDocument'时,需要* IXMLDocument'? –
顺便提一下,在这个例子中设置'Active:= True'是多余的,因为当'LoadFromFile()'出现没有错误时'Active'已经为True。 –
这里没有太多东西要走。也许你可以提供XML。 –