Validate XML using Windows DOM and TXMLDocument: doesn't work on some computers

后端 未结 2 1716
逝去的感伤
逝去的感伤 2021-01-01 08:01

I have some Delphi code to read and validates XML files based on an XSD document. I am using using Windows DOM (TMXLDocument). This Article explains the underlying logic.<

2条回答
  •  南方客
    南方客 (楼主)
    2021-01-01 08:19

    I know this question is tagged for Delphi, but I thought some Embarcadero C++ Builder users might benefit from seeing a C++ implementation of Remy's last example using MSXML2 OLE objects.

    I know I wish someone would have posted this a few days ago. XD

    .h file:

    //------------------------------------------------------------------------------
    #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 file:

    //------------------------------------------------------------------------------
    #include 
    #pragma hdrstop
    //------------------------------------------------------------------------------
    #include "XmlValidatorU.h"
    #include 
    //------------------------------------------------------------------------------
    #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 );
    }
    //------------------------------------------------------------------------------
    

提交回复
热议问题