【问题标题】:XDocument with inline schema. SchemaInfo is null具有内联模式的 XDocument。架构信息为空
【发布时间】:2012-08-24 17:30:25
【问题描述】:

好的,我们开始吧。我有一组要加载到我的应用程序中的 XML 文档。在我的小测试中,我创建了一个针对 XML 文档指定的模式进行验证的阅读器。使用下面的代码效果很好。

// Set the validation settings.
XmlReaderSettings settings = new XmlReaderSettings();
settings.ValidationType = ValidationType.Schema;
settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema;
settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
settings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
settings.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack);

// Create the XmlReader object.
XmlReader reader = XmlReader.Create("xml/note.xml", settings);

// Load the XDocument from the reader
XDocument loadedDoc = XDocument.Load(reader);

现在我的 XML 文档已正确加载,发生的任何验证错误都由回调处理。

但是,如果我想通过对某个元素调用 GetSchemaInfo() 来获取有关该元素的架构信息,我会得到 null。 This question here 谈到使用重载的 Validate 方法,但这并不真正适用于这种情况,除非我遗漏了什么。

是否可以使用内联模式将模式信息加载到 XDoc 中,或者我应该以其他方式这样做吗?

【问题讨论】:

    标签: c# xml xsd linq-to-xml


    【解决方案1】:

    查看my answer 我自己的问题。

    代码块之后的第一段对你来说很重要,但基本上,SchemaInfo会在那里,但直到之后才会添加验证回调。

    我使用的解决方法基本上是这样的(注意:此代码经过测试并且在直接加载 XML 并在 XmlSchemaSet 上调用 XDocument.Validate 时有效,但前提应该与 XmlReader 和内联相同或相似模式):

    List<XElement> errorElements = new List<XElement>();
    
    serializedObject.Validate((sender, args) =>
    {
        var exception = (args.Exception as XmlSchemaValidationException);
    
        if (exception != null)
        {
            var element = (exception.SourceObject as XElement);
    
            if (element != null)
                errorElements.Add(element);
         }
    
    });
    
    foreach element in errorElements
    {
        var si = element.GetSchemaInfo; 
    
        // do something with SchemaInfo
    }
    

    我只是想为元素捕获SchemaInfo,因此需要as 强制转换和空值检查,但这应该适用于其他节点类型,例如Attributes(虽然没有经过测试,所以我可能是错的)。

    如果您希望使用特定的回调方法而不是匿名委托,您的 errorElements 将需要是一个类级别的字段,并且您可以在验证完成后执行您需要执行的操作(同样,我将添加 untested 标签)。

    public class SomeClass
    {
    
        List<XElement> errorElements = new List<XElement>();
    
        public void Load()
        {
    
            // Set the validation settings.
            XmlReaderSettings settings = new XmlReaderSettings();
            settings.ValidationType = ValidationType.Schema;
            settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema;
            settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
            settings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
            settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
            settings.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack);
    
            // Create the XmlReader object.
            XmlReader reader = XmlReader.Create("xml/note.xml", settings);
    
            // Load the XDocument from the reader
            XDocument loadedDoc = XDocument.Load(reader);
    
            // do something with errorElements
    
        }
    
        public void ValidationCallBack(object sender, ValidationEventArgs e)
        {
            var exception = (args.Exception as XmlSchemaValidationException);
    
            if (exception != null)
            {
                var element = (exception.SourceObject as XElement);
    
                if (element != null)
                    errorElements.Add(element);
             }
    
        }
    
    }
    

    响应您关于希望 所有 节点使用 IXSchemaInfo 的评论,无论节点是失败还是通过,架构信息都会在验证后添加到 XElement,因此您的要求实际上会更容易,因为您不需要保留失败节点的列表。你应该可以这样做:

    public void Load()
    {
    
        // Set the validation settings.
        XmlReaderSettings settings = new XmlReaderSettings();
        settings.ValidationType = ValidationType.Schema;
        settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessInlineSchema;
        settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
        settings.ValidationFlags |= XmlSchemaValidationFlags.ReportValidationWarnings;
        settings.ValidationFlags |= XmlSchemaValidationFlags.ProcessSchemaLocation;
        settings.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack);
    
        // Create the XmlReader object.
        XmlReader reader = XmlReader.Create("xml/note.xml", settings);
    
        // Load the XDocument from the reader
        XDocument loadedDoc = XDocument.Load(reader);
    
        foreach (var node in loadedDoc.Descendants())
        {
            var si = node.GetSchemaInfo();
        }
    
    }
    

    上面的例子只会访问你XDocument中的XElements,但这只是为了说明我的观点。加载完成并验证 xml 后,架构信息应该在那里。

    【讨论】:

    • 感谢您的回答,我无法测试,因为我远离我的开发机器,但会尽快测试。然而,看看代码,这似乎只适用于有错误的节点。我的目标是加载所有模式信息,最好是通过验证的文档。稍后我们将使用该信息进行一些动态序列化。
    • 这个确切的代码只适用于有错误的节点,因为你只是在验证回调中收集XElements,但SchemaInfo应该仍然存在之后验证已完成所有内容,因此您可以尝试在此时进行验证(我将添加另一个示例)。
    • 遗憾的是,在以这种方式加载的元素上使用 GetSchemaInfo 会返回 null。我能够为整个文档加载架构信息的唯一方法是使用我最初引用的问题中提到的重载验证方法。它开始看起来好像我想要访问我需要以这种方式加载和验证我的文档的所有模式信息。不是不可能,只是不理想。谢谢您的帮助。欢迎任何其他想法!
    猜你喜欢
    • 1970-01-01
    • 2017-11-26
    • 1970-01-01
    • 1970-01-01
    • 2016-01-26
    • 2012-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多