7

XMLドキュメントをスキーマに対して検証しています。このコードを使用してそれらを検証しようとすると、いくつかのより複雑なドキュメント/スキーマは常に失敗します。

    DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
    dbfac.setNamespaceAware(true);
    dbfac.setIgnoringElementContentWhitespace(true);
    DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
    Document doc = docBuilder.parse("sampleResponse.xml");

    SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
    Source schemaSource = new StreamSource(getClass().getResourceAsStream("/" + "SampleResponse.xsd"));

    Schema schema = schemaFactory.newSchema(schemaSource);
    Validator validator = schema.newValidator();
    Source source = new DOMSource(doc);
    // Set a custom error handler that simple re-throws every exception
    validator.setErrorHandler(new ValidationErrorHandler());
    validator.validate(source);

問題はこの行です:

    Source schemaSource = new StreamSource(getClass().getResourceAsStream("/" + "SampleResponse.xsd"));

スキーマをファイルとして読み取ると、次のように機能します。

    Source schemaSource = new StreamSource(new File("somepath/SampleResponse.xsd"));

クラスパスからスキーマを直接取得すると、検証が機能しないのはなぜですか?

(Windows 764ビットでJava1.6を使用)

失敗した場合の例外メッセージ: Could not validate against schema SampleResponse.xsd. Nested exception: src-resolve: Cannot resolve the name 'oa:Attachments' to a(n) 'element declaration' component.

4

3 に答える 3

9

ファイルをStreamSourceに渡すと、InputStreamはファイルのコンテンツに設定されますが、systemIdもファイルのURLに設定されます。これにより、スキーマ内の相対URIを解決できます。スキーマに相対URLがある場合、これは間違いなく問題です。クラスパスからスキーマを読み取るときにこれらの相対URLを解決可能にするには、 EntityResolverを実装する必要があります。相対URIを使用しない場合でも、systemIdがnullであることが他のより微妙な影響を与える可能性があります。コンストラクターの使用をお勧めします

StreamSource(InputStream inputStream, String systemId)

systemIdをnull、スキーマを含むファイル、その他のファイル、存在しないファイルに設定してみてください。これにより、ValidatorがsystemIdで何を行っているかについてのヒントが得られる可能性があります。

于 2012-06-12T13:41:48.697 に答える
2

クラスパスから相対URLを解決できるようにするために、EntityResolverを実装する必要がないことがわかりました。

システムIDをクラスパスリソースのURIに設定するだけで十分でした。

以下は、Springを使用してクラスパス上の.xsdファイルからStreamSourceのリストを作成する実例です。

検証ソースを設定する

import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;

PathMatchingResourcePatternResolver patternResolver = new PathMatchingResourcePatternResolver();
Resource[] theResources = patternResolver.getResources("classpath:schemas/**/*.xsd");
List<Source> sources = new ArrayList<>();
for (Resource resource: theResources) {
    StreamSource dtd = new StreamSource(resource.getInputStream());
    dtd.setSystemId(resource.getURI().toString());
    sources.add(dtd);

patternResolverには、クラスパスのschemasディレクトリにclasspath:schemas/**/*.xsdあるすべての.xsdファイルを再帰的に検索できるパターンが与えられています。

.xsdファイルは、相対パスを使用して他の.xsdファイルをインポートできます。たとえば、.xsdファイルには次のようなインポートを含めることができます。

<xsd:import namespace="urn:www.example.com/common" schemaLocation="./common.xsd">

この行:

dtd.setSystemId(resource.getURI().toString());

.xsdファイルの相対パスをスキーマバリデーターで解決するための鍵です。

検証を実行します

上で構築されたStreamSource配列(sources)を使用して、XML検証用のスキーマソースを設定できるようになりました。

import org.xmlunit.builder.Input;
import org.xmlunit.validation.Languages;
import org.xmlunit.validation.Validator;
import javax.xml.transform.Source;

Validator v = Validator.forLanguage(Languages.W3C_XML_SCHEMA_NS_URI);
v.setSchemaSources(sources.toArray(new Source[sources.size()]));
Source input = Input.fromByteArray(xmlBytes).build();
v.validateInstance(input);

validateInstanceメソッド呼び出しは、 xmlBytes配列で表されるXMLを検証します。

于 2018-05-24T22:22:48.417 に答える
0

後世のために、これが私がScalaで行ったことです。これは、Joman68の回答https://stackoverflow.com/a/50518995/434405に触発されたもので、スプリングライブラリを使用していません。

import javax.xml.XMLConstants
import javax.xml.transform.Source
import javax.xml.transform.stream.StreamSource
import javax.xml.validation.{Schema, SchemaFactory, Validator}

object SchemaCheck extends App {

  private val xsds = List("schema.xsd") // add more as required

  private val schemaDocuments: Array[Source] = xsds.map { xsd =>
    val res = getClass.getResource(s"/$xsd")
    val dtd = new StreamSource(res.toURI.toString)
    dtd.setSystemId(res.toURI.toString)
    dtd
  }.toArray

  private val sf           = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI)
  private val s: Schema    = sf.newSchema(schemaDocuments)
  private val v: Validator = s.newValidator()

  private val instanceDocument: Source = new StreamSource(new java.io.File("test.xml"))
  v.validate(instanceDocument)
}
于 2020-10-14T13:01:25.803 に答える