TransformerFactory – 避免网络查找以validationDTD

我需要为XML文档的离线转换编程。 在使用以下内容加载原始XML文件时,我能够停止DTD网络查找:

DocumentBuilderFactory factory; factory = DocumentBuilderFactory.newInstance(); factory.setValidating(false); factory.setNamespaceAware(true); factory.setFeature("http://xml.org/sax/features/namespaces", false); factory.setFeature("http://xml.org/sax/features/validation", false); factory.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false); factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); // open up the xml document docbuilder = factory.newDocumentBuilder(); doc = docbuilder.parse(new FileInputStream(m_strFilePath)); 

但是,我无法将其应用于TransformerFactory对象。 DTD在本地可用,但我不知道如何指示变换器查看本地文件而不是尝试进行网络查找。

从我所看到的,变压器需要这些文件来正确地进行转换。

有关信息,我正在将MusicXML文档从Partwise转换为Timewise。

正如您可能已经猜到的那样,XSLT不是我的强项(远非如此)。

我是否需要修改XSLT文件以引用本地文件,还是可以采用不同的方式?


继续下面的评论,这里是xsl文件的摘录。 这是我看到的唯一一个引用外部文件的地方:

   

上述技术对此也有效吗?

DTD文件包含对许多MOD文件的引用,如下所示:

  

我认为这些文件也将依次导入。

好的,这是适合我的答案。

第1步:加载原始文档,关闭工厂内的validation和dtd加载。

 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); // stop the network loading of DTD files factory.setValidating(false); factory.setNamespaceAware(true); factory.setFeature("http://xml.org/sax/features/namespaces", false); factory.setFeature("http://xml.org/sax/features/validation", false); factory.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false); factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); // open up the xml document DocumentBuilder docbuilder = factory.newDocumentBuilder(); Document doc = docbuilder.parse(new FileInputStream(m_strFilePath)); 

第二步:现在我已将文档存入内存……并在检测到我需要对其进行转换后 –

 TransformerFactory transformfactory = TransformerFactory.newInstance(); Templates xsl = transformfactory.newTemplates(new StreamSource(new FileInputStream((String)m_XslFile))); Transformer transformer = xsl.newTransformer(); Document newdoc = docbuilder.newDocument(); Result XmlResult = new DOMResult(newdoc); // now transform transformer.transform( new DOMSource(doc.getDocumentElement()), XmlResult); 

我需要这样做,因为我之后继续进行进一步的处理,并且不希望输出到文件和重新加载的开销。

小解释:

诀窍是使用已关闭所有validationfunction的原始DOM对象。 你可以在这里看到:

 transformer.transform( new DOMSource(doc.getDocumentElement()), // <<----- XmlResult); 

这已通过网络访问TURNED OFF进行了测试。 所以我知道没有更多的网络查找。

但是,如果DTD,MOD等在本地可用,那么,根据建议,使用EntityResolver就是答案。 这将再次应用于原始docbuilder对象。

我现在有一个存储在newdoc中的转换文档,随时可以使用。

我希望这会有助于其他人。

您可以使用Apache xml-commons-resolver之类的库,并编写目录文件以将Web URL映射到相关文件的本地副本。 要将此目录连接到变换器机制,您需要使用SAXSource而不是StreamSource作为样式表的源:

 SAXSource styleSource = new SAXSource(new InputSource("file:/path/to/stylesheet.xsl")); CatalogResolver resolver = new CatalogResolver(); styleSource.getXMLReader().setEntityResolver(resolver); TransformerFactory tf = TransformerFactory.newInstance(); tf.setURIResolver(resolver); Transformer transformer = tf.newTransformer(styleSource); 

在Java中执行此操作的常用方法是使用LSResourceResolver将系统ID(和/或公共ID)解析为本地文件。 这在http://docs.oracle.com/javase/7/docs/api/org/w3c/dom/ls/LSResourceResolver.html中有记录。 除了标准的Java XML解析器function之外,您不需要任何其他function来实现此function。