1

xsl を使用して xml ファイルを変換するコードがあります。コードの平和は次のとおりです。私の問題は、実行ポイントを実行すると、次のエラーが表示されることです。

StackTrace: javax.xml.transform.TransformerException: javax.xml.transform.TransformerException: com.sun.org.apache.xml.internal.utils.WrappedRuntimeException: /home/app/myapp/bin/xhtml11-flat.dtd (No such file or directory)
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:720)
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:313)
    at com.core.util.XmlUtils.transform(XmlUtils.java:151)
    at com.core.util.XmlUtils.transform(XmlUtils.java:147)

簡単に言えば、アプリケーションを実行した場所から bin ディレクトリ内の dtd ファイルを見つけようとしています。

/home/app/myapp/bin/xhtml11-flat.dtd

このファイルをbinディレクトリにコピーすると、xhtml11-flat.dtdファイルがあり、binディレクトリの代わりにクラスパスからロードしたいのですが、最小限の変更でこれを達成するにはどうすればよいですか? パスを設定できるように、どこから .dtd コードをロードしているのかわかりません。

//Execution Point
function transform(){
    Templates templates = getTemplates();
    StringWriter result = new StringWriter();
    XmlUtils.transform(templates.newTransformer(), input, new StreamResult(result));

    ...
}

private Templates getTemplates() throws Exception {
    if (templates == null) {
        templates = XmlUtils.createTemplates(XslRdcSourceDocTransformer.class.getResourceAsStream("/xsl/" + getXslFileName()));
    }
    return templates;
}


public static Templates createTemplates(InputStream stream) throws Exception {
    TransformerFactory tfactory = TransformerFactory.newInstance();
    return tfactory.newTemplates(new StreamSource(stream));
}
4

1 に答える 1

5

xml ファイルには、dtd への相対パスを含む doctype 宣言が含まれている可能性があります。

<!DOCTYPE html SYSTEM "xhtml11-flat.dtd">

トランスフォーマー API は、このパスを Java プログラムの現在の作業ディレクトリに解決しようとします。パスの解決方法をカスタマイズするには、EntityResolver. これは、クラスパスからロードされた dtd のコピーへEntityResolverの参照を返すことができます。InputSource

public InputSource resolveEntity(final String publicId, final String systemId) throws SAXException {
    if ("xhtml11-flat.dtd".equals(systemId)) {
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        InputSource is = new InputSource();
        is.setSystemId(systemId);
        is.setByteStream(cl.getResourceAsStream("/com/example/dtd/xhtml11-flat.dtd"));
        return is;
    } else {
        return null;
    }
}

このクラスの使用方法は、変換のソースのタイプによって異なります。の場合、DOMSource次を構成する必要がありますDocumentBuilder

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(false);
factory.setNamespaceAware(true);

DocumentBuilder builder = factory.newDocumentBuilder();
DocumentBuilder builder = ...
builder.setEntityResolver(entityResolver);

Source source = new DOMSource(builder.parse(inputStream));

SAXSource設定がインスタンス上にある場合XMLReader:

SAXParserFactory factory1 = SAXParserFactory.newInstance();
factory1.setValidating(false);
factory1.setNamespaceAware(true);

SAXParser parser = factory1.newSAXParser();
XMLReader xmlreader = parser.getXMLReader();
xmlreader.setEntityResolver(entityResolver);

Source source = new SAXSource(xmlreader, new InputSource(stream));

XmlUtils変換のコードは、ソースの種類に関係なく同じで、現在クラスにあるコードと似ている必要があります。

Templates templates = ...
Result result = new StreamResult(...);
Transformer transformer = templates.newTransformer();
transformer.transform(source, result);
于 2012-12-20T17:39:29.630 に答える