XDocument.Validate - 错误元素

时间:2015-05-29 11:19:27

标签: .net xml date datetime xsd-validation

我有一个类,它根据提供的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

1 个答案:

答案 0 :(得分:0)

您在之前的评论中写道:

"我想知道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,我现在变得太生疏了)

&#39;希望这会有所帮助。