我尝试使用XSLT转换XML文档。作为输入,我有www.wordpress.org XHTML源代码,XSLT是虚拟示例检索站点的标题(实际上它什么都不做 - 它不会改变任何东西)。
我使用的每个API或库,转换大约需要2分钟!如果你看看wordpress.org源代码,你会发现它只有183行代码。正如我用Google搜索,这可能是由于DOM树的构建。无论XSLT多么简单,它总是2分钟 - 所以它确认它与DOM构建有关,但无论如何我不应该花2分钟。
这是一个示例代码(没什么特别的):
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = null;
try {
transformer = tFactory.newTransformer(
new StreamSource("/home/pd/XSLT/transf.xslt"));
} catch (TransformerConfigurationException e) {
e.printStackTrace();
}
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
System.out.println("START");
try {
transformer.transform(new SAXSource(new InputSource(
new FileInputStream("/home/pd/XSLT/wordpress.xml"))),
new StreamResult(outputStream));
} catch (TransformerException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("STOP");
System.out.println(new String(outputStream.toByteArray()));
在START和STOP之间,java“暂停”2分钟。如果我查看处理器或内存使用情况,则不会增加任何内容。看起来JVM真的停了......
您是否有过转换长度超过50的XML(这是随机数;))的经验?当我读到XSLT时,总是需要构建DOM树才能完成它的工作。快速转型对我来说至关重要。
提前致谢, 彼得
答案 0 :(得分:9)
示例HTML文件是否使用命名空间?如果是这样,您的XML解析器可能正在尝试从命名空间URI中检索内容(可能是模式)。如果每次运行只需要两分钟 - 这可能是一次或多次TCP超时。
您可以通过计算实例化InputSource
对象(实际解析WordPress XML)所需的时间来验证这一点,因为这可能是导致延迟的行。在查看您发布的示例文件后,它确实包含一个声明的命名空间(xmlns="http://www.w3.org/1999/xhtml"
)。
要解决此问题,您可以实现自己的EntityResolver
,这实际上会禁用基于URL的解决方案。您可能需要使用DOM - 请参阅DocumentBuilder
的{{3}}方法。
以下是使用DOM并禁用解析的示例(注意 - 这是未经测试的):
try {
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbFactory.newDocumentBuilder();
db.setEntityResolver(new EntityResolver() {
@Override
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
return null; // Never resolve any IDs
}
});
System.out.println("BUILDING DOM");
Document doc = db.parse(new FileInputStream("/home/pd/XSLT/wordpress.xml"));
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer(
new StreamSource("/home/pd/XSLT/transf.xslt"));
System.out.println("RUNNING TRANSFORM");
transformer.transform(
new DOMSource(doc.getDocumentElement()),
new StreamResult(outputStream));
System.out.println("TRANSFORMED CONTENTS BELOW");
System.out.println(outputStream.toString());
} catch (Exception e) {
e.printStackTrace();
}
如果您想使用SAX,则必须使用setEntityResolver
SAXSource
使用自定义解析器。
答案 1 :(得分:2)
发布可能存在于EntityResolver中的答案的评论者可能是正确的。但是,解决方案可能不是简单地不加载模式,而是从本地文件系统加载它们。
所以你可以做这样的事情
db.setEntityResolver(new EntityResolver() {
@Override
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
try {
FileInputStream fis = new FileInputStream(new File("classpath:xsd/" + systemId));
InputSource is = new InputSource(fis);
return is
} catch (FileNotFoundException ex) {
logger.error("File Not found", ex);
return null;
}
}
});
答案 2 :(得分:1)
问题不在于调用transfomer.transform。你更有可能在你的xslt中做一些永远需要的东西。我的建议是使用像Oxygen或XML Spy这样的工具来分析你的XSLT并找出执行时间最长的模板。一旦确定了这一点,就可以开始优化模板了。
答案 3 :(得分:0)
如果您正在Android设备上调试代码,请确保在没有附加到该进程的eclipse的情况下进行尝试。当我调试我的应用程序xslt转换需要8秒,其中相同的过程在本机代码中的ios上花了十分之一秒。一旦我运行没有附加eclipse的代码,该过程花费了相当多的时间给基于c的对手。