2015-05-29 8 views
6

Ho una classe che convalida il documento XML fornito contro XSD fornito. Nella classe chiamo il metodo XDocument.Validate per eseguire la convalida, e ottenendo il seguente errore:XDocument.Validate - Dati previsti Tipo di elemento errore

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.

Il valore di elemento è stato impostato da una variabile .NET DateTime, che in definitiva regola con il tempo parte inclusa, poiché non v'è nessun equivalente di xs: data type in .NET.

I valori per gli elementi vengono impostati da un modulo generico, quindi non è possibile selezionare e selezionare gli elementi e personalizzare l'impostazione dei loro valori. Lo sviluppatore mi invia un valore in un tipo DateTime .NET, che a sua volta chiama il metodo XElemet.SetValue(value) per impostarlo.

Inoltre, il file XSD è fuori dal mio controllo. Quindi la modifica dell'XSD non è un'opzione.

C'è un modo per sapere qual è il tipo previsto di XElement che ha causato l'errore? Una volta che lo so, posso semplicemente digitare o personalizzare il mio codice di conseguenza. Quindi, per esempio in questo caso, se so che il tipo previsto è xs:date (e non xs:datetime), posso semplicemente typecast il valore in entrata.

Qui è la mia classe di convalida, se questo aiuta:

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 

Ecco la funzione che è imposta i valori nodo 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 
+0

Che cosa vorresti digitare _to_? Come hai detto, non esiste una classe 'System.Date'. –

+0

Voglio sapere che cosa XSD si aspetta per quell'elemento - 'xs: date' o' xs: time' o 'xs: datetime', indipendentemente dal valore impostato per l'elemento. Il resto posso gestire in modo appropriato. –

+0

Quindi, per esempio, se so che l'errore è stato perché ho fornito datetime anziché solo data, posso semplicemente fare 'XElement.SetValue (value.ToString (" yyyy-MM-dd "))'. –

risposta

0

Hai scritto in un commento precedente:

"Voglio sapere qual è il XSD si aspetta per questo elemento"

Poi, tenere a mente che si può sfruttare il primo parametro "mittente "dei vostri gestori di validazione, per esempio, adapting this MSDN sample come, ad esempio,

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

Ciò può produrre un output informazioni sufficienti sui colpevoli riconoscibili all'interno del documento, si spera:

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

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

In ogni caso, una volta che si conosce il colpevole nel documento valido, allora si ha maggiore possibilità di correlare in modo più affidabile con le definizioni corrispondenti nello schema (s) utilizzato per questa convalida (che si basa solo sulla stringa di errore di convalida dello schema).

(spiacente per la risposta in C# la sintassi, ma preferisco non scrivo in VB.NET non corretta, sto diventando troppo arrugginito con, ormai)

'Spero che questo aiuti.

Problemi correlati