Правильно ли Xerces-J провалить слабую проверку для неразрешенного xsi:type?
У меня проблема с проверкой этого SOAP Envelope
используя этот фрагмент кода (ниже).
Я получаю ошибку:
org.xml.sax.SAXParseException; cvc-elt.4.2: невозможно преобразовать ipo:UKAddress в определение типа для элемента shipTo.
SOAP XSD определяет Body
как:
<xs:complexType name="Body">
<xs:sequence>
<xs:any namespace="##any" minOccurs="0" maxOccurs="unbounded" processContents="lax"/>
</xs:sequence>
Я ожидаю, что "слабый" должен проверять, если у него есть определение, но игнорировать, если его нет. Однако это не относится к xsi:type="ipo:UKAddress"
, Я только проверяю SOAP Envelope
- не Body
,
Это похоже на ошибку в xerces-j. В этом же фрагменте кода XMLSchemaValidator.java: 2152 фактически проверяет processContents перед возникновением ошибки:
else if (wildcard != null && wildcard.fProcessContents == XSWildcardDecl.PC_STRICT) {
Принимая во внимание, что XMLSchemaValidator.java: 2178 не делает такой проверки и будет выбрасывать несмотря ни на что.
fCurrentType = getAndCheckXsiType(element, xsiType, attributes);
Для меня это выглядит как ошибка в xerces-j. Кроме того, эта проблема существует в Java 8. Любая помощь или подтверждение того, что это действительно ошибка, приветствуется.
package com.example.xmlvalidate;
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.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>";
private static final String SOAP_1_1_ENVELOPE =
"http://schemas.xmlsoap.org/soap/envelope";
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.validate(domSource);
}
}
1 ответ
Краткий ответ: в данном случае Xerces является, несомненно, правильным или не доказуемо неправильным.
Длинный ответ:
Вы не указываете, используете ли вы XSD 1.0 или XSD 1.1.
В версии 1.0 спецификация немного неясно о влиянии на допустимость атрибута xsi:type, значение QName которого не разрешается в определении типа в схеме. Одно естественное прочтение правила валидации: оценка валидности схемы (элемент) в 3.3.4 - это когда xsi:type
происходит, оно должно разрешиться (обратите внимание на небольшую путаницу в тексте между требованиями соответствия и требованиями действительности). Другое прочтение правила гласит, что если пункт 1.2.1.2.3 правила валидации не применяется, то ясно, что пункты 1.2.1.2, 1.2 и 1 не применяются, что приводит к выводу, что элемент должен быть слабым оценены.
Те же самые два чтения относятся к пункту 4.2 Правил валидации: Элемент локально действителен (Элемент) в том же разделе. В этом предложении говорится, что значение xsi:type "должно разрешаться до определения типа", что означает либо недопустимость элемента, если значение xsi:type не разрешается, либо (при другом чтении правила), что в этом case элемент явно (как известно, не является) локально действительным по отношению к указанному типу.
В версии 1.1 правила были переписаны и, возможно, прояснены. Если значение xsi:type является QName, которое не разрешается в определении типа, тогда вычисляется резервный тип, и элемент проверяется на соответствие резервному типу; в случае, если вы имеете в виду, этот тип будет xsd:anyType. Но в 1.1 также очень четко указано, что в этом случае сам атрибут xsi:type является недопустимым (пункт 5 правила валидации: атрибут локально действителен в 3.2.4.
Таким образом, в соответствии с правилами XSD 1.1 ясно, что Xerces правильно помечает ввод как недопустимый, хотя код ошибки может быть более правдоподобным.
Если вы работаете с XSD 1.0, из кода ошибки ясно, что Xerces берет первый взгляд на неразрешимое значение xsi:type и рассматривает его как ошибку достоверности. Я думаю, что из текста спецификации трудно доказать, что это единственно возможная интерпретация, но еще сложнее доказать, что это неправильно: это явно правдоподобная интерпретация спецификации. Если вы хотите, чтобы проблемы с xsi:type игнорировались и не рассматривались как ошибки валидности, вам нужен пропускаемый подстановочный знак, а не слабый подстановочный. (Конечно, вы можете объявить свою собственную обертку элемента для полезной нагрузки SOAP, объявив ее с помощью символа пропуска в своей модели содержимого и, таким образом, принудительно запустить желаемое поведение проверки.)