0

XSD スキーマに対して XML ファイルを検証する必要があります。スキーマは、(include および import ディレクティブを使用して) 複数の XSD ファイルに分散されます。

SO の投稿で既に見つけた質問/回答に従うことで、次の解決策を思いつきました。

(次のコードは急速に開発されたプロトタイプであり、最終的な解決策ではないことに注意してください。)

private static final String PROJECT_ROOT_DIR_PATH = "--- project-root-path ---";
private static final String SCHEMAS_ROOT_PATH = "--- schemas root path ---";

private void validate() throws Exception
{
    DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
    builderFactory.setNamespaceAware(true);

    DocumentBuilder parser = builderFactory.newDocumentBuilder();

    // parse the XML into a document object
    Document document = parser.parse(
        new File(
            PROJECT_ROOT_DIR_PATH +
            "src\\test\\resources\\example.xml"
        )
    );

    SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);

    // associate the schema factory with the resource resolver, which is responsible for resolving the imported XSD's
    factory.setResourceResolver(new ResourceResolver(PROJECT_ROOT_DIR_PATH + SCHEMAS_ROOT_PATH));

    Schema schema = factory.newSchema(
        new File(
            PROJECT_ROOT_DIR_PATH +
            SCHEMAS_ROOT_PATH +
            "--- root-xsd-file-path\\root-schema.xsd ---"
        )
    );

    Validator validator = schema.newValidator();
    validator.validate(new DOMSource(document));
}

ResourceResolver.java:

public class ResourceResolver implements LSResourceResolver 
{   
    @Override
    public LSInput resolveResource(String type, String namespaceURI,
        String publicId, String systemId, String baseURI) 
    {
        if (!"http://www.w3.org/2001/XMLSchema".equals(type))
        {
            throw new IllegalArgumentException(
                "Unexpected resource type [" + type + "]."
            );
        }

        if (systemId == null)
        {
            throw new IllegalArgumentException(
                "Unexpected resource system-id [" + systemId + "]."
            );
        }

        System.out.println("base-uri: " + baseURI);
        System.out.println("system-id: " + systemId);

        URI targetURI = getTargetURI(baseURI, systemId);
        System.out.println("target-uri: " + targetURI);

        System.out.println("---");

        Input input = null;

        try {
            input = new Input(baseURI, publicId, systemId, targetURI.toURL().openStream());
        } 
        catch (Exception ex)
        {
            throw new RuntimeException(
                "Could not open resource stream - " + ex.getMessage()
            );
        }

        return input;
    }

    private static URI getTargetURI(String baseURI, String relativePath)
    {
        URI targetURI = null;

        try {
            targetURI = (new URI(baseURI)).resolve(relativePath);
        }
        catch (URISyntaxException ex)
        {
            throw new RuntimeException(
                "Could not resolve target URI - " + ex.getMessage()
            );
        }

        return targetURI;
    }
}

入力.java:

public class Input implements LSInput 
{
    private BufferedInputStream inputStream;

    private String baseURI;
    private String publicId;
    private String systemId;

    public Input(String baseURI, String publicId, String sysId, InputStream input) 
    {
        this.baseURI = baseURI;
        this.publicId = publicId;
        this.systemId = sysId;
        this.inputStream = new BufferedInputStream(input);
    }

    public String getPublicId() 
    {
        return publicId;
    }

    public void setPublicId(String publicId) 
    {
        this.publicId = publicId;
    }

    public String getBaseURI() 
    {
        return baseURI;
    }

    public InputStream getByteStream() 
    {
        return null;
    }

    public boolean getCertifiedText() 
    {
        return false;
    }

    public Reader getCharacterStream() 
    {
        return null;
    }

    public String getEncoding() 
    {
        return null;
    }

    public String getStringData() 
    {
        synchronized (inputStream) 
        {
            try {
                return IOUtils.toString(inputStream);
            } 
            catch (IOException e) {
                e.printStackTrace();
                System.out.println("Exception " + e);
                return null;
            }
        }
    }

    public void setBaseURI(String baseURI) {
    }

    public void setByteStream(InputStream byteStream) {
    }

    public void setCertifiedText(boolean certifiedText) {
    }

    public void setCharacterStream(Reader characterStream) {
    }

    public void setEncoding(String encoding) {
    }

    public void setStringData(String stringData) {
    }

    public String getSystemId() {
        return systemId;
    }

    public void setSystemId(String systemId) {
        this.systemId = systemId;
    }

    public BufferedInputStream getInputStream() 
    {
        return inputStream;
    }

    public void setInputStream(BufferedInputStream inputStream) 
    {
        this.inputStream = inputStream;
    }
}

このソリューションが生成するログを観察すると、実際には include/import ステートメントを深さ優先検索の順序で処理しているように見えます。

ただし、一部の import ステートメントは無視されます (たとえば、まったく処理されません)。

どのステートメントが処理され、どのステートメントが処理されないかのパターンを見つけることができませんでした。たとえば、ファイルの次の 3 行を処理する場合、最初と最初の行のみが処理されます。それらはすべて私と同等に見えますが。

<import namespace="schemas/src/x20130601" schemaLocation="../../x20130601/Personalnumber.xsd"/>
<import namespace="schemas/src/common/2008/01/03" schemaLocation="../../../contract/x20080103/Contractnumber.xsd"/>
<import namespace="schemas/src/20100504" schemaLocation="../../../system/x20100504/Contractidentification.xsd" />

一部の import ステートメントが無視されるという事実は、次のタイプの例外につながります。

Exception in thread "main" org.xml.sax.SAXParseException; systemId: file:/z:/--- project path ---/schemas//x20130504/Identification.xsd; lineNumber: 18; columnNumber: 61; src-resolve: Cannot resolve the name 'dat20080103:Contractnumber' to a(n) 'element declaration' component.

欠落したドキュメントの宣言は、スキップされた XSD ファイルにあります。


エラーを探す場所や追加情報を教えてください。

4

0 に答える 0