C++\CLI - 如何将成员函数设置为 xmlDocument::Schemas::ValidationEventHandler 的处理程序

C++\CLI - How to set a member function as a handler to xmlDocument::Schemas::ValidationEventHandler

我试图在 Visual Studio 2012 中将成员函数设置为 XmlC++/CLI 中的文档数据成员的处理程序。处理函数如下所示...

void Validate ( System :: Object ^ sender, System :: Xml :: Schema :: ValidationEventArgs ^ xmlException ) {

            switch ( xmlException->Severity ) {

                case System :: Xml :: Schema :: XmlSeverityType :: Error : {

                    System :: Console :: WriteLine ( "Object: {0}", sender->ToString () );
                    System :: Console :: WriteLine ( " Error: {0}", xmlException->Message );

                } break;

                case System :: Xml :: Schema :: XmlSeverityType :: Warning : {

                    System :: Console :: WriteLine ( " Object: {0}", sender->ToString () );
                    System :: Console :: WriteLine ( "Warning: {0}", xmlException->Message );

                } break;

                default : {

                    System :: Console :: WriteLine ( "An unknown XML Exception has occured:\n\n   Object: {0}", sender->ToString () );
                    System :: Console :: WriteLine ( "Exception: {0}", xmlException->Message );

                } break;

            }

        };

...没什么特别的。

这就是我的数据成员的样子...

System :: Xml :: XmlDocument ^ xmlDocument;

...这就是我试图在 class 构造函数中设置它的方式:

xmlDocument->Schemas->ValidationEventHandler += gcnew System :: Xml :: Schema :: ValidationEventArgs ( this, & MyClass :: Validate );

我的问题是我收到错误 C3767:无法访问候选函数,即使我的 "Validate" 成员函数和它定义的 class 被指定为 public.

我尝试了多种方法,最近尝试使用 EventArgs 或使用“#pragma make_public (System :: Xml :: Schema :: ValidationEventArgs )”,但是没用。

我 运行 没有头发可以拔出我的头,所以任何帮助将不胜感激。谢谢大家。

首先,您收到编译器错误 C3767 的原因是您需要执行以下操作:

schemas->ValidationEventHandler += gcnew System::Xml::Schema::ValidationEventHandler(this, &MyClass::Validate); 

而不是 gcnew ValidationEventArgs

其次,请注意 XmlSchemaSet.ValidationEventHandler 可能不会按照您的想法行事。来自 documentation:

Sets an event handler for receiving information about schema validation errors when the Add or Compile methods of the XmlSchemaSet are called.

因此,如果您要为无效的 XML 文档添加事件处理程序,这不是它。这是针对模式本身的错误。

如果你想制作一个 class 来包装 XmlDocument 但也允许调用者加载模式并验证 XmlDocument 反对它,你可以做这样的事情:

public ref class MyClass
{
public:
    MyClass()
    {
        xmlDocument = gcnew System::Xml::XmlDocument();
        schemas = gcnew System::Xml::Schema::XmlSchemaSet();
        // Set the callback for errors in the schema itself.
        schemas->ValidationEventHandler += gcnew System::Xml::Schema::ValidationEventHandler(this, &MyClass::ValidateSchema);   
        xmlDocument->Schemas = schemas;
    }

    // Adds a schema to the current schema set.
    void AddSchema(System::String ^targetNamespace, System::String ^schemaUri);

    // Loads the specified document, validating it against the current schema set.
    void LoadDocument(System::String ^inputUri);

    // Validates the current document against the current schema set.
    void ValidateDocument();

    System::Xml::XmlDocument ^ GetDocument() { return xmlDocument; }

private:
    // Validation callback for errors in the schema itself.
    void ValidateSchema ( System :: Object ^ sender, System :: Xml :: Schema :: ValidationEventArgs ^ xmlException );

    // Validation callback for errors in the XML document.
    void ValidateXml ( System :: Object ^ sender, System :: Xml :: Schema :: ValidationEventArgs ^ xmlException );

    // Lower level callback for both schema and XML errors.
    void Validate ( System :: Object ^ sender, System :: Xml :: Schema :: ValidationEventArgs ^ xmlException, System::String ^ prefix );

    System::Xml::XmlDocument ^ xmlDocument;

    System::Xml::Schema::XmlSchemaSet ^schemas;
};

单独缓存 XmlSchemaSet 很方便,因为当使用 XmlReader 的 XML 数据初始化 XmlDocument 时,XmlDocument.Schemas 对象从 reader.

Schemas 属性(重新)加载

那么原型实现如下所示:

#include "stdafx.h"

#using <mscorlib.dll>
#using <System.dll>
#using <System.Xml.dll>

using namespace System;
using namespace System::Xml;
using namespace System::Xml::Schema;

void MyClass::AddSchema(System::String ^targetNamespace, System::String ^schemaUri)
{
    try
    {
        schemas->Add(targetNamespace, schemaUri);
        xmlDocument->Schemas = schemas;
    }
    catch (Exception ^ex)
    {
        Console::WriteLine(ex->ToString());
        // Possibly rethrow.
    }
}

void MyClass::LoadDocument (System::String ^inputUri)
{
    XmlReader^ reader = nullptr;
    try
    {
        ValidationEventHandler^ eventHandler = gcnew System::Xml::Schema::ValidationEventHandler(this, &MyClass::ValidateXml);  

        XmlReaderSettings^ settings = gcnew XmlReaderSettings();

        settings->Schemas = schemas;
        settings->ValidationType = ValidationType::Schema;
        settings->ValidationEventHandler += eventHandler;

        reader = XmlReader::Create(inputUri, settings);

        xmlDocument->Load(reader);
        reader->Close();
    }
    catch (Exception ^ex)
    {
        Console::WriteLine(ex->Message);
        // Possibly rethrow.
    }
    finally
    {
        // Make sure the reader is closed in the event of an exception.
        delete reader;
    }
}

void MyClass::ValidateDocument()
{
    ValidationEventHandler^ eventHandler = gcnew System::Xml::Schema::ValidationEventHandler(this, &MyClass::ValidateXml);

    xmlDocument->Validate(eventHandler);
}

void MyClass::ValidateSchema ( System :: Object ^ sender, System :: Xml :: Schema :: ValidationEventArgs ^ xmlException)
{
    Validate(sender, xmlException, gcnew System::String("Schema: "));
}

void MyClass::ValidateXml ( System :: Object ^ sender, System :: Xml :: Schema :: ValidationEventArgs ^ xmlException )
{
    Validate(sender, xmlException, System::String::Empty);
}

void MyClass::Validate ( System :: Object ^ sender, System :: Xml :: Schema :: ValidationEventArgs ^ xmlException, System::String ^ prefix )
{
    switch ( xmlException->Severity ) 
    {
    case System :: Xml :: Schema :: XmlSeverityType :: Error : 
        {
            System :: Console :: WriteLine ( prefix + "Object: {0}", sender->ToString () );
            System :: Console :: WriteLine ( prefix + " Error: {0}", xmlException->Message );

        } break;

    case System :: Xml :: Schema :: XmlSeverityType :: Warning : 
        {
            System :: Console :: WriteLine ( prefix + " Object: {0}", sender->ToString () );
            System :: Console :: WriteLine ( prefix + "Warning: {0}", xmlException->Message );

        } break;

    default : 
        {
            System :: Console :: WriteLine ( prefix + "An unknown XML Exception has occured:\n\n   Object: {0}", sender->ToString () );
            System :: Console :: WriteLine ( prefix + "Exception: {0}", xmlException->Message );

        } break;
    }
};