I am having a problem validating this SOAP Envelope using this snippet of code
(below).
The error that I get is:
org.xml.sax.SAXParseException; cvc-elt.4.2: Cannot resolve 'ipo:UKAddress' to a
type definition for element 'shipTo'.
SOAP XSD defines the Body as:
<xs:complexType name="Body">
<xs:sequence>
<xs:any namespace="##any" minOccurs="0" maxOccurs="unbounded"
processContents="lax"/>
</xs:sequence>
My expectation is that "lax" should validate if it has a definition, but ignore
if it does not. However, that is not the case with respect to the
xsi:type="ipo:UKAddress". I am only validating the SOAP Envelope - not the
Body.
It looks like a bug in xerces-j. In the same chunk of code,
XMLSchemaValidator:2152 actually checks processContents before raising an error:
else if (wildcard != null && wildcard.fProcessContents ==
XSWildcardDecl.PC_STRICT) {
Whereas, XMLSchemaValidator:2178 makes no such check and will throw no matter
what.
fCurrentType = getAndCheckXsiType(element, xsiType, attributes);
Any help, or confirmation that this is indeed a bug is appreciated.
Thanks,
Jamie
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.CodeSource;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import org.apache.xerces.impl.Constants;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
public class Validate {
private static final String envelope =
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
"<soapenv:Envelope \n" +
" xmlns=\"http://www.w3.org/2001/XMLSchema\"" +
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
" xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\"\n" +
" >\n" +
" <soapenv:Body>\n" +
" <ipo:purchaseOrder
xmlns:ipo=\"http://www.example.com/IPO\">\n" +
" <shipTo exportCode=\"1\" xsi:type=\"ipo:UKAddress\">\n" +
" <name>Helen Zoe</name>\n" +
" <street>47 Eden Street</street>\n" +
" <city>Cambridge</city>\n" +
" <postcode>CB1 1JR</postcode>\n" +
" </shipTo>\n" +
" </ipo:purchaseOrder>\n" +
" </soapenv:Body>\n" +
"</soapenv:Envelope>";
protected static final String HONOUR_ALL_SCHEMALOCATIONS =
Constants.XERCES_FEATURE_PREFIX +
Constants.HONOUR_ALL_SCHEMALOCATIONS_FEATURE;
protected static final String IGNORE_XSI_TYPE_FEATURE =
Constants.XERCES_FEATURE_PREFIX + Constants.IGNORE_XSI_TYPE_FEATURE;
private static final String SOAP_1_1_ENVELOPE =
"http://schemas.xmlsoap.org/soap/envelope";
protected static final String JAXP_SCHEMA_LANGUAGE =
"http://java.sun.com/xml/jaxp/properties/schemaLanguage";
protected static final String W3C_XML_SCHEMA =
"http://www.w3.org/2001/XMLSchema";
public static void validate() throws ParserConfigurationException,
SAXException, IOException, TransformerException {
final DocumentBuilderFactory documentBuilderFactory =
DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
documentBuilderFactory.setValidating(false);
final Class<?> clazz = documentBuilderFactory.getClass();
final CodeSource source = clazz.getProtectionDomain().getCodeSource();
System.out.println("Document builder implementation: " +
clazz.getName() + " from : " + (source == null ? "JRE" : source));
final DocumentBuilder documentBuilder =
documentBuilderFactory.newDocumentBuilder();
final InputStream is = new
ByteArrayInputStream(envelope.getBytes(StandardCharsets.UTF_8));
final Document document = documentBuilder.parse(is);
final DOMSource domSource = new DOMSource(document);
final StreamSource streamSource = new StreamSource(new
URL(SOAP_1_1_ENVELOPE).openStream());
final SchemaFactory schemaFactory =
SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
final Schema schema = schemaFactory.newSchema(streamSource);
final Validator validator = schema.newValidator();
validator.setFeature("http://apache.org/xml/features/validation/schema/ignore-xsi-type-until-elemdecl",
true);
validator.setFeature("http://apache.org/xml/features/honour-all-schemaLocations",
true);
validator.setFeature("http://apache.org/xml/features/validation/schema-full-checking",
false);
validator.validate(domSource);
}
}