我需要为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文件的摘录。这是我看到的唯一一个引用外部文件的地方:
<!--
XML output, with a DOCTYPE refering the timewise DTD.
Here we use the full Internet URL.
-->
<xsl:output method="xml" indent="yes" encoding="UTF-8"
omit-xml-declaration="no" standalone="no"
doctype-system="http://www.musicxml.org/dtds/timewise.dtd"
doctype-public="-//Recordare//DTD MusicXML 2.0 Timewise//EN" />
上述技术对此也有效吗?
DTD文件包含对许多MOD文件的引用,如下所示:
<!ENTITY % layout PUBLIC
"-//Recordare//ELEMENTS MusicXML 2.0 Layout//EN"
"layout.mod">
我认为这些文件也会依次导入。
答案 0 :(得分:5)
好的,这是适合我的答案。
第1步:加载原始文档,关闭工厂内的验证和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);
我需要这样做,因为我之后会进行进一步的处理,并且不希望输出到文件和重新加载的开销。
小解释:
诀窍是使用已关闭所有验证功能的原始DOM对象。你可以在这里看到:
transformer.transform(
new DOMSource(doc.getDocumentElement()), // <<-----
XmlResult);
已通过网络访问已关闭测试。 所以我知道没有更多的网络查找。
但是,如果DTD,MOD等在本地可用,那么,根据建议,使用EntityResolver就是答案。这将再次应用于原始的 docbuilder 对象。
我现在有一个存储在 newdoc 中的转换文档,随时可以使用。
我希望这会对别人有所帮助。
答案 1 :(得分:0)
您可以使用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);
答案 2 :(得分:0)
在Java中执行此操作的常用方法是使用LSResourceResolver将系统ID(和/或公共ID)解析为本地文件。这在http://docs.oracle.com/javase/7/docs/api/org/w3c/dom/ls/LSResourceResolver.html记录。除了标准的Java XML解析器功能之外,您不需要任何其他功能来实现这一功能。