XDocument.Validate - 错误元素的预期数据类型

Posted

技术标签:

【中文标题】XDocument.Validate - 错误元素的预期数据类型【英文标题】:XDocument.Validate - Expected Data Type of error element 【发布时间】:2015-08-12 05:48:18 【问题描述】:

我有一个根据提供的 XSD 验证提供的 XML 文档的类。在类中我调用XDocument.Validate 方法进行验证,得到如下错误:

'http://www.example.com/enrollrequest1:requested-payment-date' 元素无效 - 值“2015-05-28T00:00:00”无效 根据其数据类型'http://www.w3.org/2001/XMLSchema:date' - 字符串 '2015-05-28T00:00:00' 不是有效的 XsdDateTime 值。

元素的值是从.NET DateTime 变量中设置的,该变量最终将其设置为包含时间部分,因为在 .NET 中没有等效的 xs:date 类型。

元素的值是从通用模块设置的,因此我无法挑选元素并自定义设置它们的值。开发人员向我发送 .NET DateTime 类型的值,我的程序又调用 XElemet.SetValue(value) 方法来设置它。

另外,XSD 文件不在我的控制范围内。所以修改 XSD 不是一种选择。

有没有办法知道导致错误的 XElement 的预期类型是什么? 一旦我知道了,我就可以相应地进行类型转换或自定义我的代码。因此,例如在这种情况下,如果我知道预期的类型是 xs:date(而不是 xs:datetime),我可以简单地对传入的值进行类型转换。

这是我的验证器类,如果有帮助的话:

Option Strict On
Imports System.XML.Schema

Public Class XmlSchemaValidator
    Public ReadOnly Errors As New List(Of String)

    Private XDoc As XDocument
    Private Schemas As XmlSchemaSet

    Public Sub New(ByVal doc As XDocument, ByVal schemaUri As String, ByVal targetNamespace As String)
        Me.XDoc = doc
        Me.Schemas = New XmlSchemaSet
        Me.Schemas.Add(targetNamespace, schemaUri)
    End Sub

    Public Sub Validate()
        Errors.Clear()
        XDoc.Validate(Schemas, AddressOf XsdErrors)
    End Sub

    Private Sub XsdErrors(ByVal sender As Object, ByVal e As ValidationEventArgs)
        Errors.Add (e.Message)
    End Sub
End Class

这是设置 xml 节点值的函数。

Function SetValue(ByVal xmlDoc As XDocument, ByVal keyValues As Dictionary(Of String, Object)) As Boolean
    '' set values
    For Each kvp In keyValues
        Dim xe As XElement = xmlDoc.Root.XPathSelectElement(kvp.Key)

        ''-- this is buggy implementation for handling xs:date vs xs:datetime that needs to be corrected...
        'If TypeOf kvp.Value Is DateTime AndAlso DirectCast(kvp.Value, DateTime).TimeOfDay = TimeSpan.Zero Then
        '    xe.SetValue(DirectCast(kvp.Value, DateTime).ToString("yyyy-MM-dd"))
        'Else
        xe.SetValue(kvp.Value)
        'End If
    Next

    '' validate final document
    Dim schemaValidator As New XmlSchemaValidator(xmlDoc, schemaFile, "")
    schemaValidator.Validate()
    If schemaValidator.Errors.Count > 0 Then
        'Error Logging code goes here...
        Return False
    End If
    Return True
End Function

【问题讨论】:

你会什么类型?正如你所说,没有System.Date 类。 我想知道 XSD 对该元素的期望 - xs:datexs:timexs:datetime,无论为元素设置了什么值。其余的我可以妥善处理。 例如,如果我知道错误是因为我提供了日期时间而不是仅提供日期,我可以简单地执行XElement.SetValue(value.ToString("yyyy-MM-dd")) 见msdn.microsoft.com/en-us/library/xya3a402.aspx hmm.. http://www.w3.org/2001/XMLSchema:date 意味着预期的类型正是xs:date。那么为什么不从验证错误消息中得到预期的类型呢? 【参考方案1】:

您在之前的评论中写道:

“我想知道 XSD 对该元素的期望”

然后,请记住,您可以利用验证处理程序的第一个参数“sender”,例如,adapting this MSDN sample,例如,

        string xsdMarkup =
 @"<xsd:schema xmlns:xsd='http://www.w3.org/2001/XMLSchema'>
   <xsd:element name='Root'>
    <xsd:complexType>
     <xsd:sequence>
      <xsd:element name='Child1' minOccurs='1' maxOccurs='1'/>
      <xsd:element name='Child2' minOccurs='1' maxOccurs='1'/>
     </xsd:sequence>
    </xsd:complexType>
   </xsd:element>
  </xsd:schema>";
        XmlSchemaSet schemas = new XmlSchemaSet();
        schemas.Add("", XmlReader.Create(new StringReader(xsdMarkup)));

        // (just for debug spying)
        var schemata = new XmlSchema[1];
        schemas.CopyTo(schemata, 0);

        XDocument errorDoc = new XDocument(
            new XElement("Root",
                new XElement("Child1", "content1"),
                new XElement("Child2", "content2"),
                new XElement("Child2", "content3") // (must fail validation on maxOccurs)
            )
        );

        Console.WriteLine();
        Console.WriteLine("Validating errorDoc");
        errorDoc.Validate(schemas, (sender, args) =>
        
            Console.WriteLine("0", args.Message); // (what you're already doing)
            Console.WriteLine();
            // but there's also:
            var xElement = sender as XElement;
            if (xElement != null)
            
                Console.WriteLine("Element 0 invalid : 1", xElement, e.Exception.Message);
            
        );

        Console.ReadKey();

这可以产生一个输出,其中包含有关文档中可识别的罪魁祸首的足够信息,希望:

Validating errorDoc
The element 'Root' has invalid child element 'Child2'.

Element <Child2>content3</Child2> invalid : The element 'Root' has invalid child element 'Child2'.

无论如何,一旦您知道无效文档中的罪魁祸首,那么您就有更好的机会更可靠地与用于此验证的架构中的相应定义相关联(而不是仅仅依赖架构验证错误字符串)。

(对不起,C# 语法的答案,但我宁愿不写不正确的 VB.NET,我现在太生疏了)

'希望这会有所帮助。

【讨论】:

以上是关于XDocument.Validate - 错误元素的预期数据类型的主要内容,如果未能解决你的问题,请参考以下文章

未捕获的错误:模板解析错误:'mat-label' 不是已知元素:

除第一个元素外的所有元素的分段错误

元素不可见错误(无法单击元素)

为啥即使元素存在,硒也会抛出未找到元素的错误? [复制]

分段错误:从二维向量中随机删除元素

Javascript For循环附加子元素只附加第一个元素,然后抛出错误