2

Java の XSD 検証ライブラリによって提供されるエラー メッセージのテキストに問題があります。私の場合、Apache Xerces が内部で使用されているようです。私は、Java からのエラーが非常に誤解を招くと思います。

Javaから取得しているエラーは次のとおりです。

cvc-complex-type.2.4.b: 要素 'ルート' の内容が完全ではありません。「{subnode1, subnode2}」のいずれかが必要です。

しかし、別の XML エディターである XMLSpy 2004 は、次のように述べています。

「subnode1」の後の「」には必須要素が必要です: subnode2、subnode3

サブノード 1 が欠落していないため、ここでは 2 番目のエラーの方がはるかに正確であるように見えます。ただし、subnode2 と subnode3 は両方ともそうです。

ここに私のXMLファイルがあります:

<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="schema.xsd">
    <subnode0/>
    <subnode1/>
</root>

これは私が使用したXSDです:

<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="root" type="NodeType">
    </xs:element>

    <xs:complexType name="NodeType">
        <xs:sequence>
            <xs:element name="subnode0" type="subnode0_Type" minOccurs="0" maxOccurs="unbounded"/>
            <xs:element name="subnode1" type="subnode1_Type" minOccurs="0" maxOccurs="unbounded"/>
            <xs:element name="subnode2" type="subnode2_Type" minOccurs="1" maxOccurs="1"/>
            <xs:element name="subnode3" type="subnode3_Type" minOccurs="1" maxOccurs="1"/>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="subnode0_Type">
    </xs:complexType>
    <xs:complexType name="subnode1_Type">
    </xs:complexType>
    <xs:complexType name="subnode2_Type">
    </xs:complexType>
    <xs:complexType name="subnode3_Type">
    </xs:complexType>
</xs:schema>

そして、これが検証 API を呼び出す Java コードです。

public class XsdErrorTextMain {

    private final static DocumentBuilder documentBuilder;
    private final static SchemaFactory schemaFactory;

    static {
        try {
            final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            documentBuilderFactory.setNamespaceAware(true);
            documentBuilder = documentBuilderFactory.newDocumentBuilder();
        } catch (final ParserConfigurationException e) {
            throw new RuntimeException(e);
        }

        schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
    }

    public static void main(final String[] args) throws Exception {
        final Document xmlDocument = readXmlFile("file.xml");
        final Schema schema = readXsdFile("schema.xsd");

        runXmlValidation(xmlDocument, schema);
    }

    private static void runXmlValidation(final Document xmlDocument, final Schema schema) throws SAXException {
        try {
            final Validator validator = schema.newValidator();
            validator.setErrorHandler(new ErrorHandler() {

                @Override
                public void warning(final SAXParseException exception) {
                    return;
                }

                @Override
                public void error(final SAXParseException exception) throws SAXException {
                    displayValidationError(exception);
                }

                @Override
                public void fatalError(final SAXParseException exception) throws SAXException {
                    throw new RuntimeException("A fatal error was raised during the validation", exception);
                }
            });

            validator.validate(new DOMSource(xmlDocument));
        } catch (final IOException e) {
            throw new RuntimeException(e);
        }
    }

    private static void displayValidationError(final SAXParseException validationError) {
        System.out.println("Line: " + validationError.getLineNumber());
        System.out.println("Column: " + validationError.getColumnNumber());
        System.out.println("Message: " + validationError.getMessage());
    }

    private static Document readXmlFile(final String path) throws IOException, SAXException {
        try (final InputStream xmlInputStream = ClassLoader.getSystemResource(path).openStream()) {
            return documentBuilder.parse(xmlInputStream);
        }
    }

    private static Schema readXsdFile(final String path) throws IOException, SAXException {
        final Document xsdDocument = readXmlFile(path);
        return schemaFactory.newSchema(new DOMSource(xsdDocument));
    }
}

ここで何か不足していますか?エラーメッセージをより正確に計算できる他の実装を知っていますか? どんな入力でも大歓迎です。ありがとう!

4

1 に答える 1

1

厳密に言えば、あなたが XMLSpy 2004 と呼んでいるものによってあなたに与えられたメッセージは誤解を招くものです。サブノード 1 の「無制限」の maxOccurs を考えると、最後に遭遇したサブノード 1 の後に何が来るかを確実に言うことはできません。

唯一確かなことは、エラーが発生した時点で、subnode1 または subnode2 のいずれかが続く可能性があるということです。

そして、これはまさにあなたが得ている他のメッセージです(あなたが言うXerces、ところでそれは標準の.NETのものと一致します)あなたに伝えます...

誰かがこの情報を使用して、有効な XML を構築するために必要な手順をユーザーに実行させるエディタを構築するとします (例: Intellisense、またはグラフィカル エディタのコンテキスト メニュー)。ユーザーを誘導するのにどちらが優れていると思いますか? Xerces メッセージを正しいものとして呼び出すのは、単純に、サブノード 1 を入力すると、XML Spy 2004 メッセージがノード 2 と 3 だけを示唆し続けるからです (2 を入力しなかった場合、なぜ 3 なのか)。 ? subnode1 を追加し続けたい場合はどうすればよいですか?)

つまり、これらのメッセージに何を期待するかによって異なります。ただし、私の個人的な見解では、Xerces (および前述の .NET も同様) のメッセージは、私が説明した種類のタスクに対して正しいものであるということです。一部の人々は、それが反復的すぎると感じるかもしれません。つまり、subnode2 にヒットした後でのみ、subnode3 を「準備」するように言われるでしょう...あなたの問題だと思います...

しかし、あなたが示したノードのセット全体がオプションのシーケンスでラップされ、そのシーケンスの後に必須のサブノード4が続く別のシナリオを想像してみてください....あなたの場合、メッセージは'' after 'subnode1': subnode2, subnode3, subnode4. そして、上で言及したオプションのシーケンスが繰り返されている場合はどうなるでしょうか?

最後に、XSD モデルの性質を考えると、この「先読み」を実装して可能性を与えることができます...問題は、情報が役に立たなくなるポイントまでオプションが簡単に合成されることです...次は常に今まででよかった。

于 2013-10-18T13:53:20.130 に答える