我有一些Delphi代码来读取和验证基于XSD文档的XML文件。我正在使用Windows DOM(TMXLDocument)。本文解释了底层逻辑。
它在某些计算机上工作(例如,对有问题的标记抛出异常)。但在较新的计算机上,它不会引发任何异常。
Windows中是否有需要更改才能使其正常工作的设置?或者有人知道用于验证XML的本机Delphi组件吗?
XSD文件:http://www.nemsis.org/media/XSD/EMSDataSet.xsd
示例XML(注意E02\U 02需要有一个基于xsd xyz.com/DataSet.xsd的正值
<EMSDataSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.nemsis.org" xsi:schemaLocation="http://myfakedomain.com/DataSet.xsd">
<Header>
<Record>
<E02>
<E02_01>123</E02_01>
<E02_02>0</E02_02>
</E02>
</Record>
</Header>
</EMSDataSet>
德尔福代码:
XMLDoc:= TXMLDocument.Create(nil);
try
XMLDoc.ParseOptions:= [poResolveExternals, poValidateOnParse];
XMLDoc.LoadFromFile(filetocheck);
XMLDoc.Active:= True;
except
on E:EDOMParseError do begin
showMessage(e.Message);
end;
end;
例外情况:
The element: '{http://www.nemsis.org}E02_02' has an invalid value according to its data type. Line: 20 <E02_02>0</E02_02>
我知道这个问题是为Delphi标记的,但我认为一些Embarcadero C Builder用户可能会从使用MSXML2 OLE对象的Remy最后一个示例的C实现中受益。
我知道我希望有人能在几天前发布这个。XD公司
. h文件:
//------------------------------------------------------------------------------
#ifndef XmlValidatorUH
#define XmlValidatorUH
//------------------------------------------------------------------------------
class PACKAGE TXmlValidator
{
private:
Variant FSchemaCache;
Variant FXmlDomDoc;
// TAutoCmd Variables
Procedure CacheProcAdd;
PropertySet CacheSetValidateOnLoad;
Procedure XmlProcLoadXml;
PropertySet XmlSetValidateOnParse;
PropertySet XmlSetResolveExternals;
PropertySet XmlSetSchemas;
PropertyGet XmlGetParseError;
PropertyGet ParseErrorGetReason;
public:
__fastcall TXmlValidator( String _SchemaLocation );
String __fastcall ValidationError( String _Xml );
};
//------------------------------------------------------------------------------
#endif
. cpp文件:
//------------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
//------------------------------------------------------------------------------
#include "XmlValidatorU.h"
#include <System.Win.ComObj.hpp>
//------------------------------------------------------------------------------
#pragma package(smart_init)
//------------------------------------------------------------------------------
// Validates XML against Schema
//------------------------------------------------------------------------------
// This class uses OLE objects from MSXML2 to validate XML from an XSD file.
// Generally, use the following steps to deal with OLE objects:
// 1. Define a Variant variable for your OLE Object; assign using CreateOleObject().
// 2. Define your TAutoCmd objects that will be used in Variant.Exec()
// 3. Set TAutoCmd args using << to add settings
// 4. Once everything is set up, call Exec() on your OLE Object variant
// More documentation on OLE objects / TAutoCmd at:
// http://docwiki.embarcadero.com/CodeExamples/Rio/en/AutoCmd_(C%2B%2B)
//------------------------------------------------------------------------------
// This macro clarifies that we're registering OLE Function names to our defined TAutoCmd variables.
//
#define RegisterAutoCmd( _AutoCmd, _OleFunc ) _AutoCmd( _OleFunc )
//------------------------------------------------------------------------------
// These macros clear AutoCmdArgs before setting them.
// I made these because setting an arg multiple times just stacks them up, changing the function signature.
// Then, OLE throws a "Member Not Found" error because it can't find a function with that signature.
//
#define AutoCmdArg( _AutoCmd, _Arg ) _AutoCmd.ClearArgs(); _AutoCmd << _Arg
#define AutoCmdArgs( _AutoCmd, _Arg1, _Arg2 ) AutoCmdArg( _AutoCmd, _Arg1 ); _AutoCmd << _Arg2
//------------------------------------------------------------------------------
__fastcall TXmlValidator::TXmlValidator( String _SchemaLocation )
:
RegisterAutoCmd( CacheProcAdd, "add" ),
RegisterAutoCmd( CacheSetValidateOnLoad, "validateOnLoad" ),
RegisterAutoCmd( XmlProcLoadXml, "loadXML" ),
RegisterAutoCmd( XmlSetValidateOnParse, "validateOnParse" ),
RegisterAutoCmd( XmlSetResolveExternals, "resolveExternals" ),
RegisterAutoCmd( XmlSetSchemas, "schemas" ),
RegisterAutoCmd( XmlGetParseError, "parseError" ),
RegisterAutoCmd( ParseErrorGetReason, "reason" )
{
if ( _SchemaLocation.IsEmpty() )
{
throw Exception( String( __FUNC__ ) + " - Missing Schema Location" );
}
// Instantiate the OLE objects
FSchemaCache = CreateOleObject( "MSXML2.XMLSchemaCache.4.0" );
FXmlDomDoc = CreateOleObject( "MSXML2.DOMDocument.4.0" );
// Set static args that shouldn't change
AutoCmdArg( CacheSetValidateOnLoad, true );
AutoCmdArg( XmlSetValidateOnParse, true );
AutoCmdArg( XmlSetResolveExternals, true );
const AnsiString NoNameSpace = "";
AutoCmdArgs( CacheProcAdd, NoNameSpace, AnsiString( _SchemaLocation ) );
// Load Cache
FSchemaCache.Exec( CacheSetValidateOnLoad ); // Validate on Load
FSchemaCache.Exec( CacheProcAdd ); // Add Schema file location to the cache
// Now that the cache is loaded, set cached schema as arg to XML
AutoCmdArg( XmlSetSchemas, FSchemaCache );
}
//------------------------------------------------------------------------------
String __fastcall TXmlValidator::ValidationError( String _Xml )
{
AutoCmdArg( XmlProcLoadXml, AnsiString( _Xml ) );
FXmlDomDoc.Exec( XmlSetValidateOnParse );
FXmlDomDoc.Exec( XmlSetResolveExternals );
FXmlDomDoc.Exec( XmlSetSchemas );
FXmlDomDoc.Exec( XmlProcLoadXml );
Variant ParseErr = FXmlDomDoc.Exec( XmlGetParseError );
return ParseErr.Exec( ParseErrorGetReason );
}
//------------------------------------------------------------------------------
使用MSXML时,TXMLDocument不直接支持启用XSD验证,因此由MSXML负责管理。为此,启用poResolveExternals和poValidateOnParse标志很重要,但还有一些其他因素需要考虑。最重要的是,尽管MSXML确实支持从XML中引用XSD,但它在加载XML时是否实际使用引用的XSD上有一些限制:
在文档中引用XSD模式
要从MSXML 6.0中的XML文档引用XML模式(XSD)模式,可以使用以下任何一种方法将模式链接到XML文档,以便MSXML使用该模式验证文档内容。
>
在加载或解析XML文档之前,将XSD模式文件添加到模式缓存,然后将该缓存连接到DOM文档或SAX阅读器。
...
在您要验证的XML文档中显式声明和使用命名空间前缀的情况下,xsi: SchemaLocat属性可以很好地工作。
以下示例显示了引用外部XSD模式MyData的XML文档。xsd用于验证“urn:MyData”命名空间URI中的节点,该URI映射到“MyData:”命名空间前缀。
<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文件配对并用于验证以“MyData:”开头的元素和属性节点,架构需要使用并包含以下架构属性:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:MyData="urn:MyData"
targetNamespace="urn:MyData"
elementFormDefault="qualified">
这些属性声明“urn:MyData”命名空间URI和“MyData:”命名空间前缀,以便它们与XML文件中的这些声明完全一致。如果它们不匹配,则在验证期间将永远不会调用指定位置的架构。
您尚未显示XSD,但显示的XML不符合上述文档中提到的规则。特别是,您缺少使用urn命名空间映射,以及要验证的XML节点上的前缀。MSXML的某些版本可能会比其他版本更好地处理此问题,这可以解释为什么验证在某些机器上工作,而在其他机器上被忽略,这取决于安装的MSXML版本。
尽管如此,您可能不得不采用文档中提到的第二种方法:
这需要直接使用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连接到解析器,您必须知道XSD的位置。因此,只需加载一次XML即可提取XSD位置,然后将XSD加载到模式缓存中,然后重新加载附加了XSD的XML。以下是一些Delphi示例:
delphi中msxml的模式验证
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;
如何根据XML模式验证IXMLDocument?
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文档、模式和验证
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.
问题内容: 我已经构建了一个默认情况下使用SQL Server CE 4.0的应用程序,但也可以使用单独的SQL Server(SQL Server Express)。 我已经将它部署到办公室周围的大约10台计算机上,并且除了其中2台之外,它工作正常:副总裁和质量检查人员,当然:-/ 在这些计算机上,每个数据库访问大约需要30秒!如果我安装了SQL Server Express 2008 R2,并
我正在尝试通过url读取pdf。我遵循了许多stackoverflow建议并使用PyPdf2 FileReader从pdf中提取文本。我的代码如下所示: 我能够成功地提取第一个链接的文本。但是如果我对第二个pdf使用相同的程序。我没有收到任何短信。页码和文档信息似乎出现了。 我尝试通过终端从Pdfminer中提取文本,并能够从第二个pdf中提取文本。 你知道pdf有什么问题吗?或者我使用的库有缺点
我在GitHub中使用这个项目:https://github.com/gankit0701/Face-Mask-Detection-In-android-App 这个使用TensorFlow Lite for mobile(Android)。它检测一个人是否戴面具。它在面部顶部绘制一个框(红色/绿色)。 我奇怪的问题是,如果我直接在设备上安装演示APK,面罩检测工作正常。但是当我在Android
我们用FCM创建了一个带有通知的聊天应用程序,我的代码是正确的,我的设备也得到了推送通知数据,但一些中国制造的设备,如vivo、oppo、一加、小米,不允许通知显示,除非我在各自厂商的受保护的应用程序列表中添加应用程序。他们有没有办法解决这个问题。 https://hackernoon.com/notifications-in-android-are-horribly-broken-b8dbec6
我一直在尝试使用Firebase认证来实现电话认证。它和一个Android模拟器一起工作。我在模拟器中使用了一个测试号和一个实数。两个作品。但是只有测试号可以在真实设备上工作,并对其他号抛出这个异常 我也在Firebase中设置了SHA密钥。
问题内容: alert(myVar1); return false; var myVar1; 上面的代码在IE,FF和Opera中引发错误,表明return语句必须包含在函数中。但它可以在Safari和Chrome中运行(显示)。 以上代码已在全局范围内编写。以外的所有功能。 任何原因? 问题答案: 在javaScript中,将变量移到脚本顶部,然后运行。所以当你运行它会做 这是因为javascr