B4J Question Validate XML using a XSD / Json using Schema?

MathiasM

Member
Licensed User
Hello

Is it in any way possible to validate data (XML or JSON) via a so-called Schema?
I tried the search function for a lot of different search terms, but got no real results, so my hopes aren't very high!

If someone knows a way how to do this, I'm very open to any insights or ti
 

Daestrum

Well-Known Member
Licensed User
This code module code will validate xml against an xsd file
B4X:
'Static code module
Sub Process_Globals
 Private SchemaFactory As JavaObject
 Private factory As JavaObject
 Private XMLconstants As JavaObject
 Private Validator As JavaObject
 Private StreamSource As JavaObject
 Private xsd,xml As JavaObject
 Private Schema As JavaObject
End Sub
' returns true for valid and false for invalid or IO error
Sub ValidateFile(xsdFile As String,xmlFile As String) As Boolean
 XMLconstants.InitializeStatic("javax.xml.XMLConstants")
 SchemaFactory.InitializeStatic("javax.xml.validation.SchemaFactory")
 factory = SchemaFactory.RunMethod("newInstance",Array(XMLconstants.GetField("W3C_XML_SCHEMA_NS_URI")))
 xsd.InitializeNewInstance("java.io.File",Array(xsdFile))
 xml.InitializeNewInstance("java.io.File",Array(xmlFile))
 Schema = factory.RunMethod("newSchema",Array(xsd))
 Validator = Schema.RunMethod("newValidator",Null)
 StreamSource.InitializeNewInstance("javax.xml.transform.stream.StreamSource",Array(xml))
 Try
  Validator.RunMethod("validate",Array(StreamSource))
 Catch
  Log(LastException.Message)
  Return False
 End Try
 Return True 
End Sub
call it with (where xsd and xml are the full path names to the files) I called my module XMLValidator
B4X:
Log(XMLValidator.ValidateFile(xsd,xml))
If there is an error in the xml you get a log message like
org.xml.sax.SAXParseException; systemId: file:/c:/temp/Employee.xml; lineNumber: 13; columnNumber: 31; cvc-datatype-valid.1.2.1: 'A1999' is not a valid value for 'integer'.
which pretty much tells you exactly what is wrong and where.

Hope it helps.
 

Daestrum

Well-Known Member
Licensed User
Slightly improved code module - this one will list out all the errors instead of stopping at the first one it finds.
B4X:
'Static code module
Sub Process_Globals
 Private SchemaFactory As JavaObject
 Private factory As JavaObject
 Private XMLconstants As JavaObject
 Private Validator As JavaObject
 Private StreamSource As JavaObject
 Private xsd,xml As JavaObject
 Private Schema As JavaObject
 Private ErrorList As List
End Sub
' returns true for valid and false for invalid or IO error
Sub ValidateFile(xsdFile As String,xmlFile As String) As Boolean
 ErrorList.Initialize
 XMLconstants.InitializeStatic("javax.xml.XMLConstants")
 SchemaFactory.InitializeStatic("javax.xml.validation.SchemaFactory")
 factory = SchemaFactory.RunMethod("newInstance",Array(XMLconstants.GetField("W3C_XML_SCHEMA_NS_URI")))
 xsd.InitializeNewInstance("java.io.File",Array(xsdFile))
 xml.InitializeNewInstance("java.io.File",Array(xmlFile))
 Schema = factory.RunMethod("newSchema",Array(xsd))
 Validator = Schema.RunMethod("newValidator",Null)
 StreamSource.InitializeNewInstance("javax.xml.transform.stream.StreamSource",Array(xml))
 Validator.RunMethod("setErrorHandler",Array(Validator.CreateEvent("org.xml.sax.ErrorHandler","xmlerr",Null)))
 Validator.RunMethod("validate",Array(StreamSource))
 
 If ErrorList.Size > 0 Then
  For Each i As Object In ErrorList
   Log("Error "&i)
  Next
  Return False
 End If
 Return True
End Sub
Sub xmlerr_Event(method As String,args() As Object) As Object
 ErrorList.Add(args(0))
 Return True
End Sub
If you don't want the error logged twice then choose either of these code snippets to replace the 'For Each … part

B4X:
 'Technical error report
 For a = 0 To ErrorList.Size-2 Step 2
  Log(ErrorList.Get(a))
 Next
gives this output
org.xml.sax.SAXParseException; systemId: file:/c:/temp/records.xml; lineNumber: 13; columnNumber: 30; cvc-minInclusive-valid: Value '1945' is not facet-valid with respect to minInclusive '1950' for type '#AnonType_yearrecordType'.
B4X:
 'Logical error report
 For a = 1 To ErrorList.Size-1 Step 2
  Log(ErrorList.Get(a))
 Next
and this gives
org.xml.sax.SAXParseException; systemId: file:/c:/temp/records.xml; lineNumber: 13; columnNumber: 30; cvc-type.3.1.3: The value '1945' of element 'year' is not valid.
 
Last edited:

Daestrum

Well-Known Member
Licensed User
Anything available for JSON?
The JSON is a bit harder to get working as the json.jar in the built in libraries takes preference but does not have the method toMap(…) on JSONObject so fails with a method not found exception.
Still looking at ways round this.
 
Top