I need to validate the following XML against a (complex) type declared in the following XSD, using XmlBeans.
My XSD:
<xs:schema targetNamespace="http://www.xxx.com/xmlns/osb/WS2CICS/program/PROG1/p1" attributeFormDefault="unqualified" elementFormDefault="qualified"
xmlns="http://www.xxx.com/xmlns/osb/WS2CICS/program/PROG1/p1"
xmlns:ct="http://www.xxx.com/xmlns/osb/WS2CICS/common"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!--xs:element name="Param" type="ParamType"/-->
<xs:complexType name="ParamType">
<xs:sequence>
<xs:element name="Text" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
My XML:
<Param xsi:type="p1:ParamType"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.xxx.com/xmlns/osb/WS2CICS/Envelope/v01"
xmlns:p1="http://www.xxx.com/xmlns/osb/WS2CICS/program/PROG1/p1">
<p1:Text>abc</p1:Text>
</Param>
I essentially use the code from this site for XML validation using XmlBeans. But the validation fails with the message "Invalid type"
for the element "Param". The validation succeeds only after uncommenting the "Param"-element declaration in the XSD and after changing the namespace of "Param" in the XML by adding the namespace prefix p1:
to it - that is when validating against an element declaration, not a type declaration.
What I need is:
"{http://www.xxx.com/xmlns/osb/WS2CICS/Envelope/v01}Param"
in the XML root is OK (no need to check)."{http://www.xxx.com/xmlns/osb/WS2CICS/program/PROG1/p1}ParamType"
(to check the children)How am I to do that?
Background:
I have a message envelope where the "Param" element is of type "anyType", i.e. it can have any content. In a particular situation I need to check that "Param" has a particular content given by a dynamically chosen XSD. I can easily check the validity of the envelope, but in the second step, I need to check the validity of the Param too.
Edit: re-phrased
I found no direct way on how to validate an element against a XSD type, using XmlBeans. But I found a workaround by dynamically creating a schema for the missing element declaration:
/**
* Validates an XML element (it needs not be the document root) against a type declared in an XSD-schema.
*
* @param xmlObject XML element being validated
* @param schemas compiled XML schema(s) used for the validation
* @param xmlObjectType Qualified name of the schema type in <code>schemas</code> against which the element validation is performed
* @throws XmlException thrown in case of a parsing or validation error
*/
public static void validate(XmlObject xmlObject, SchemaTypeSystem schemas, QName xmlObjectType) throws XmlException {
Node node = xmlObject.getDomNode();
//..... some argument checking here .....
String elemName = node.getLocalName();
String elemNamespace = node.getNamespaceURI();
String typeName = xmlObjectType.getLocalPart();
String typeNamespace = xmlObjectType.getNamespaceURI();
String schemasKey = elemName+"@"+elemNamespace +"," +typeName+"@"+typeNamespace; //perhaps it's sufficient
// Prepare schema
SchemaTypeSystem loader = schemas;
SchemaGlobalElement schemaElem = loader.findElement(new QName(elemNamespace, elemName));
if (schemaElem != null) {
QName elemQName = schemaElem.getType().getName();
if (!elemQName.getLocalPart().equals(typeName) || !elemQName.getNamespaceURI().equals(typeNamespace))
throw new IllegalArgumentException("Requested type " +typeName+"@"+typeNamespace
+" of xmlObject is different from its actual type " +elemQName.getLocalPart()+"@"+elemQName.getNamespaceURI() +" in provided schema(s)");
}
else {
//the schema does not contain the xmlObject element declaration => add it (artificially)
String helperSchema = ""
+ "<xs:schema attributeFormDefault=\"unqualified\" elementFormDefault=\"qualified\"\n"
+ " targetNamespace=\"" +elemNamespace +"\"\n"
+ " xmlns=\"" +elemNamespace +"\"\n"
+ " xmlns:t=\"" +typeNamespace +"\"\n"
+ " xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">\n"
+ "\n"
+ " <xs:element name=\"" +elemName +"\" type=\"t:" +typeName +"\"/>\n"
+ "\n"
+ "</xs:schema>\n";
loader = XmlBeans.compileXsd(schemas, // extend the schema
new XmlObject[]{
XmlObject.Factory.parse(helperSchema, new XmlOptions().setLoadLineNumbers().setLoadMessageDigest()
.setDocumentSourceName(schemasKey))
}, null,
new XmlOptions().setErrorListener(null).setCompileDownloadUrls().setCompileNoPvrRule());
}
// validate the element using the loader in a standard way
// (see the link above, for instance)
validate(xmlObject, loader);
}
I receive an XmlObject on the input, but one would usually use a File object instead. In the implementation, resorting to DOM may not be optimal, though - if I new XmlBeans better, the code could be improved.