web-dev-qa-db-ja.com

複数のスキーマ定義に対してXMLファイルを検証する

私はいくつかの異なるスキーマに対してXMLファイルを検証しようとしています(不自然な例に対する謝罪):

  • a.xsd
  • b.xsd
  • c.xsd

特にc.xsdはb.xsdをインポートし、b.xsdはa.xsdをインポートします。

<xs:include schemaLocation="b.xsd"/>

私は次の方法でXercesを介してこれをやろうとしています:

XMLSchemaFactory xmlSchemaFactory = new XMLSchemaFactory();
Schema schema = xmlSchemaFactory.newSchema(new StreamSource[] { new StreamSource(this.getClass().getResourceAsStream("a.xsd"), "a.xsd"),
                                                         new StreamSource(this.getClass().getResourceAsStream("b.xsd"), "b.xsd"),
                                                         new StreamSource(this.getClass().getResourceAsStream("c.xsd"), "c.xsd")});     
Validator validator = schema.newValidator();
validator.validate(new StreamSource(new StringReader(xmlContent)));

しかし、これは3つのスキーマすべてを正しくインポートできず、名前「blah」をa(n) 'group'コンポーネントに解決できません。

Pythonを使用してこれを正常に検証しましたが、-Java 6.およびXerces 2.8.1で実際に問題が発生しています。誰かがここで何が問題になっているのか、または私のXMLドキュメントを検証するためのより簡単なアプローチを提案できますか?

35
Jon

したがって、他の誰かがここで同じ問題に遭遇した場合に備えて、XML Stringを検証するために、リソースとして-単体テストから親スキーマ(および暗黙の子スキーマ)をロードする必要がありました。 Xerces XMLSchemFactoryを使用してJava 6バリデーターと一緒にこれを行いました。

インクルード経由で子スキーマを正しくロードするために、カスタムリソースリゾルバーを作成する必要がありました。コードはここにあります:

https://code.google.com/p/xmlsanity/source/browse/src/com/arc90/xmlsanity/validation/ResourceResolver.Java

リゾルバーを使用するには、スキーマファクトリで指定します。

xmlSchemaFactory.setResourceResolver(new ResourceResolver());

そしてそれを使用して、クラスパスを介してリソースを解決します(私の場合はsrc/main/resourcesから)。これについてのコメントは大歓迎です...

18
Jon

http://www.kdgregory.com/index.php?page=xml.parsing セクション '単一のドキュメントに複数のスキーマ '

その文書に基づく私の解決策:

URL xsdUrlA = this.getClass().getResource("a.xsd");
URL xsdUrlB = this.getClass().getResource("b.xsd");
URL xsdUrlC = this.getClass().getResource("c.xsd");

SchemaFactory schemaFactory = schemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
//---
String W3C_XSD_TOP_ELEMENT =
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"
   + "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" elementFormDefault=\"qualified\">\n"
   + "<xs:include schemaLocation=\"" +xsdUrlA.getPath() +"\"/>\n"
   + "<xs:include schemaLocation=\"" +xsdUrlB.getPath() +"\"/>\n"
   + "<xs:include schemaLocation=\"" +xsdUrlC.getPath() +"\"/>\n"
   +"</xs:schema>";
Schema schema = schemaFactory.newSchema(new StreamSource(new StringReader(W3C_XSD_TOP_ELEMENT), "xsdTop"));
6
iolha

私は同じ問題に直面し、調査した後、この解決策を見つけました。わたしにはできる。

Enum別のXSDsを設定するには:

public enum XsdFile {
    // @formatter:off
    A("a.xsd"),
    B("b.xsd"),
    C("c.xsd");
    // @formatter:on

    private final String value;

    private XsdFile(String value) {
        this.value = value;
    }

    public String getValue() {
        return this.value;
    }
}

検証する方法:

public static void validateXmlAgainstManyXsds() {
    final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);

    String xmlFile;
    xmlFile = "example.xml";

    // Use of Enum class in order to get the different XSDs
    Source[] sources = new Source[XsdFile.class.getEnumConstants().length];
    for (XsdFile xsdFile : XsdFile.class.getEnumConstants()) {
        sources[xsdFile.ordinal()] = new StreamSource(xsdFile.getValue());
    }

    try {
        final Schema schema = schemaFactory.newSchema(sources);
        final Validator validator = schema.newValidator();
        System.out.println("Validating " + xmlFile + " against XSDs " + Arrays.toString(sources));
        validator.validate(new StreamSource(new File(xmlFile)));
    } catch (Exception exception) {
        System.out.println("ERROR: Unable to validate " + xmlFile + " against XSDs " + Arrays.toString(sources)
                + " - " + exception);
    }
    System.out.println("Validation process completed.");
}
2
Weslor

Xercesのスキーマの内容は、(a)非常に非常に知識が豊富で、(b)検出した内容が気に入らない場合、まったく役に立たないエラーメッセージを表示します。それはイライラする組み合わせです。

python=のスキーマの要素は、はるかに寛容であり、スキーマ内の小さなエラーが報告されないまま過ぎていました。

これで、c.xsdにb.xsdが含まれ、b.xsdにa.xsdが含まれている場合、3つすべてをスキーマファクトリにロードする必要はありません。これは不必要なだけでなく、Xercesを混乱させてエラーが発生する可能性があるため、これが問題である可能性があります。単にc.xsdをファクトリーに渡して、b.xsdとa.xsd自体を解決させます。これは、c.xsdに対して相対的に行う必要があります。

2
skaffman

Xercesのドキュメントから: http://xerces.Apache.org/xerces2-j/faq-xs.html

import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

...

StreamSource[] schemaDocuments = /* created by your application */;
Source instanceDocument = /* created by your application */;

SchemaFactory sf = SchemaFactory.newInstance(
    "http://www.w3.org/XML/XMLSchema/v1.1");
Schema s = sf.newSchema(schemaDocuments);
Validator v = s.newValidator();
v.validate(instanceDocument);
2
Hesse

私はこれを使ってしまいました:

import org.Apache.xerces.parsers.SAXParser;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
import Java.io.IOException;
 .
 .
 .
 try {
        SAXParser parser = new SAXParser();
        parser.setFeature("http://xml.org/sax/features/validation", true);
        parser.setFeature("http://Apache.org/xml/features/validation/schema", true);
        parser.setFeature("http://Apache.org/xml/features/validation/schema-full-checking", true);
        parser.setProperty("http://Apache.org/xml/properties/schema/external-noNamespaceSchemaLocation", "http://your_url_schema_location");

        Validator handler = new Validator();
        parser.setErrorHandler(handler);
        parser.parse("file:///" + "/home/user/myfile.xml");

 } catch (SAXException e) {
    e.printStackTrace();
 } catch (IOException ex) {
    e.printStackTrace();
 }


class Validator extends DefaultHandler {
    public boolean validationError = false;
    public SAXParseException saxParseException = null;

    public void error(SAXParseException exception)
            throws SAXException {
        validationError = true;
        saxParseException = exception;
    }

    public void fatalError(SAXParseException exception)
            throws SAXException {
        validationError = true;
        saxParseException = exception;
    }

    public void warning(SAXParseException exception)
            throws SAXException {
    }
}

変更することを忘れないでください:

1)パラメータ"http:// your_url_schema_location" xsdファイルの場所。

2)文字列"/ home/user/myfile.xml"は、xmlファイルを指すものに使用します。

変数を設定する必要はありませんでした:-Djavax.xml.validation.SchemaFactory:http://www.w3.org/2001/XMLSchema=org.Apache.xerces.jaxp.validation.XMLSchemaFactory

1
Edenshaw

念のため、複数のXSDに対してxmlまたはオブジェクトを検証するためのソリューションを見つけるために誰かがまだここに来ているので、ここで触れます

//Using **URL** is the most important here. With URL, the relative paths are resolved for include, import inside the xsd file. Just get the parent level xsd here (not all included xsds).

URL xsdUrl = getClass().getClassLoader().getResource("my/parent/schema.xsd");

SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema(xsdUrl);

JAXBContext jaxbContext = JAXBContext.newInstance(MyClass.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
unmarshaller.setSchema(schema);

/* If you need to validate object against xsd, uncomment this
ObjectFactory objectFactory = new ObjectFactory();
JAXBElement<MyClass> wrappedObject = objectFactory.createMyClassObject(myClassObject); 
marshaller.marshal(wrappedShipmentMessage, new DefaultHandler());
*/

unmarshaller.unmarshal(getClass().getClassLoader().getResource("your/xml/file.xml"));
0
Shafiul