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

时间:2021-08-13 16:34:34

I have a class which validates the supplied XML document against the supplied XSD. In the class I call the XDocument.Validate method to perform validation, and getting the following error:

我有一个类,它根据提供的XSD验证提供的XML文档。在类中,我调用XDocument.Validate方法来执行验证,并获得以下错误:

The 'http://www.example.com/enrollrequest1:requested-payment-date' element is invalid - The value '2015-05-28T00:00:00' is invalid according to its datatype 'http://www.w3.org/2001/XMLSchema:date' - The string '2015-05-28T00:00:00' is not a valid XsdDateTime value.

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

The value for element has been set from a .NET DateTime variable, which ultimately sets it with the time part included, since there is no equivalent of xs:date type in .NET.

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

The values for the elements are being set from a generic module, so I can't pick and choose elements and customize setting their values. The developer sends me value in a .NET DateTime type, which my program in turn calls the XElemet.SetValue(value) method to set it.

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

Also, the XSD file is out of my control. So modifying the XSD is not an option.

此外,XSD文件是我无法控制的。因此,修改XSD不是一种选择。

Is there a way to know what is the expected type of the XElement that caused the error? Once I know it, I can just typecast or customize my code accordingly. So for example in this case, if I know that the expected type is xs:date (and not xs:datetime), I can simply typecast the incoming value.

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

Here is my validator class, if this helps:

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

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

Here is the function that is sets the xml node values.

这是设置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 个解决方案

#1


0  

You wrote in an earlier comment:

你在之前的评论中写道:

"I want to know what the XSD is expecting for that element"

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

Then, keep in mind that you can exploit the first parameter "sender" of your validation handlers, for instance, adapting this MSDN sample as, e.g.,

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

        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();

This can yield an output with enough information on the recognizable culprits within the document, hopefully:

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

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

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

Anyway, once you know the culprit in the invalid document, then you have better chances to correlate more reliably with the corresponding definitions in the schema(s) used for this validation (than just relying on the schema validation error string).

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

(sorry for the answer in C# syntax, but I'd rather not write in incorrect VB.NET, I'm getting too rusty with, by now)

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

'Hope this helps.

'希望这可以帮助。

#1


0  

You wrote in an earlier comment:

你在之前的评论中写道:

"I want to know what the XSD is expecting for that element"

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

Then, keep in mind that you can exploit the first parameter "sender" of your validation handlers, for instance, adapting this MSDN sample as, e.g.,

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

        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();

This can yield an output with enough information on the recognizable culprits within the document, hopefully:

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

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

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

Anyway, once you know the culprit in the invalid document, then you have better chances to correlate more reliably with the corresponding definitions in the schema(s) used for this validation (than just relying on the schema validation error string).

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

(sorry for the answer in C# syntax, but I'd rather not write in incorrect VB.NET, I'm getting too rusty with, by now)

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

'Hope this helps.

'希望这可以帮助。