XmlDocument.NodeInserted 在 XmlDocument.Validate() 上触发

XmlDocument.NodeInserted triggered on XmlDocument.Validate()

我目前正在编写一个应用程序来修改和处理特定的 XML 文档。

我的应用程序有一个堆栈用于撤消/重做更改,并且还会将 XML DOM 上的更改记录到调试控制台。在每次更改 DOM 时,应用程序都会验证文档,因此用户会直接获得有关无效条目的反馈。

我的问题是,XmlDocument.Validate() 方法触发了 XmlDocument.NodeInserted 操作。这会导致无休止的回调循环。 我怎样才能防止这种行为?

我的部分代码:
正在初始化/加载文档:

private void ParseStyleSheet(FileInfo stylesFile)
    {
        // load document
        XmlDocument document = new XmlDocument();
        document.PreserveWhitespace = true;
        document.Schemas = StyleSchemaSet.GetSchemaset();
        document.Load(stylesFile.FullName);
        // add event handlers
        document.NodeChanged += XmlNodeChangedAction;
        document.NodeChanged += _undoMngr.XmlNodeChangedEventHandler;
        document.NodeInserted += XmlNodeChangedAction;
        document.NodeInserted += _undoMngr.XmlNodeChangedEventHandler;
        document.NodeRemoved += XmlNodeChangedAction;
        document.NodeRemoved += _undoMngr.XmlNodeChangedEventHandler;
        // set namespace
        XmlNamespaceManager nameSpaceMngr = new 
        XmlNamespaceManager(document.NameTable);
        ...
}

更改处理程序/验证回调:

    private void XmlNodeChangedAction(object src, XmlNodeChangedEventArgs args)
    {
        // debug outputs
        Debug.WriteLine("XML node is changing");
        Debug.Indent();
        Debug.WriteLine(args.Action);
        Debug.WriteLine("Old: " + args.OldValue);
        Debug.WriteLine("New: " + args.NewValue);
        _document.Validate(this.ValidationEventCallBack);//TODO leads to loop
        // undindent debug
        Debug.Unindent();
    }


    private void ValidationEventCallBack(object sender, ValidationEventArgs args)
    {
        switch (args.Severity)
        {
            case XmlSeverityType.Error:
                //TODO maybe throw for GUI message?
                Debug.WriteLine("XSD Error: " + args.Message);
                break;

            case XmlSeverityType.Warning:
                Debug.WriteLine("XSD Warning: " + args.Message);
                break;

            default:
                break;
        }
    }

一旦更改节点,就会出现无休止的更改循环,这也会显示在调试器控制台中:

XML node is changing
Change
Old: 20px
New: 25px
XML node is changing
    Insert
    Old: #ebebeb
    New: #ebebeb
    XML node is changing
        Insert
        Old: #ebebeb
        New: #ebebeb
        XML node is changing
            Insert
            Old: #ebebeb
            New: #ebebeb
            XML node is changing
                Insert
                ...




更新(感谢陶老师的提示):
如果在加载之后和添加 NodeInserted 委托之前直接验证了文档,则不再发生循环。就像这样,由于第一次验证,所有 DOM 更改都已经发生。

private void ParseStyleSheet(FileInfo stylesFile)
    {
        // load document
        XmlDocument document = new XmlDocument();
        document.PreserveWhitespace = true;
        document.Schemas = StyleSchemaSet.GetSchemaset();
        document.Load(stylesFile.FullName);
        document.Validate(ValidationEventCallBack);
        // add event handlers
        document.NodeChanged += XmlNodeChangedAction;
        document.NodeChanged += _undoMngr.XmlNodeChangedEventHandler;
        document.NodeInserted += XmlNodeChangedAction;
        document.NodeInserted += _undoMngr.XmlNodeChangedEventHandler;
        document.NodeRemoved += XmlNodeChangedAction;
        document.NodeRemoved += _undoMngr.XmlNodeChangedEventHandler;
        ...
    }

The documentation for Validate() 说:

The Validate method performs infoset augmentation. Specifically, after successful validation, schema defaults are applied, text values are converted to atomic values as necessary, and type information is associated with validated information items. The result is a previously un-typed XML sub-tree in the XmlDocument replaced with a typed sub-tree.

我觉得您需要添加一些额外的状态来跟踪更改是 "intentional",还是验证期间发生的 "infoset augmentation" 的结果。类似于跟踪 "IsValidating" 状态并避免在该状态下调用 _document.Validate() 之类的东西。