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。 –