0

我遇到了这个我似乎无法弄清楚的奇怪问题。到目前为止,我的转换方法似乎几乎完美无缺,但我目前正在构建的工具让我有些头疼。

这是我的方法:

这个可以正常工作并生成正确的 XML

    public static void transform(String filename, String filePath, String stylesheetPath, String outputTo, boolean prettyPrint, boolean excludeDeclaration) throws TransformerException, IOException {
        if (!new File(outputTo).exists()) new File(outputTo).mkdir();

        TransformerFactory factory = TransformerFactory.newInstance();
        Source xsl = new StreamSource(new File(stylesheetPath));
        Templates template = factory.newTemplates(xsl);
        Transformer transformer = template.newTransformer();
        if (!prettyPrint) {
            transformer.setOutputProperty(OutputKeys.INDENT, "no");
        } else {
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
        }
        if (excludeDeclaration) transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");

        Source xml = new StreamSource(new File(filePath + filename));
        OutputStream outputStream = new FileOutputStream(outputTo + filename);
        transformer.transform(xml, new StreamResult(outputStream));
        outputStream.close();
    }

使用相同的 XSLT,以下生成的 XML(或来自 XML 的内容)仅包含 Text 节点(无元素、属性等)

    public static Document transformInMemory(Document xmlDoc, String stylesheetPath) throws TransformerException, ParserConfigurationException, SAXException, IOException {
        TransformerFactory factory = TransformerFactory.newInstance();
        Source xsl = new StreamSource(new File(stylesheetPath));
        Templates template = factory.newTemplates(xsl);
        Transformer transformer = template.newTransformer();
        transformer.setOutputProperty(OutputKeys.INDENT, "no");
        transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "0");

        DOMSource source = new DOMSource(xmlDoc);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        transformer.transform(source, new StreamResult(baos));

        System.out.println(baos.toString());

        // load into DocumentBuilder
        DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = domFactory.newDocumentBuilder();
        InputSource is = new InputSource(new ByteArrayInputStream(baos.toByteArray()));
        return builder.parse(is);
    }

从我一直在做的所有搜索来看,我在第二种方法中似乎没有做错任何事情,但它肯定会产生一些奇怪的结果。

示例结果(不幸的是,我无法发布实际数据,所以我只是将文本替换为其他数据)

    <?xml version="1.0" encoding="UTF-8"?>








                     Some Text Here









                                                        A.



                                                   Some other text here









                                                        B.



                                                   Some more text here









                                                        C.



                                                   And more text here









                                                        D.



                                                   Even more text here















                     A

                1

我故意将结果格式化,以便您可以准确地看到我所看到的。上面的结果就是System.out.println(baos.toString());. 如果我在控制台(Eclipse)中突出显示文本,缩进都在那里,但所有元素等都没有显示出来。

所以,我的问题是:谁能告诉我可能发生了什么?为什么第一个工作没有任何问题,但第二个导致上述结果?

编辑:

在玩弄了我的方法之后,我想出了一个似乎可行的解决方法。我没有使用DOMSource,而是将 xmlDoc 转换为InputStream,但这似乎有点笨拙。DOMSource关于为什么会导致这个问题的任何想法?

    public static Document transformInMemory(Document xmlDoc, String stylesheetPath) throws TransformerException, ParserConfigurationException, SAXException, IOException {
        TransformerFactory factory = TransformerFactory.newInstance();
        Source xsl = new StreamSource(new File(stylesheetPath));
        Templates template = factory.newTemplates(xsl);
        Transformer transformer = template.newTransformer();
        transformer.setOutputProperty(OutputKeys.INDENT, "no");
        transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "0");

        // convert the xmlDoc to an inputstream
        ByteArrayOutputStream xmlOutStream = new ByteArrayOutputStream();
        Source domSource = new DOMSource(xmlDoc);
        Result result = new StreamResult(xmlOutStream);
        TransformerFactory.newInstance().newTransformer().transform(domSource, result);
        InputStream in = new ByteArrayInputStream(xmlOutStream.toByteArray());

        //DOMSource source = new DOMSource(xmlDoc);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        Source source = new StreamSource(in);
        transformer.transform(source, new StreamResult(baos));

        System.out.println("baos -> " + baos.toString());

        // load into DocumentBuilder
        DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = domFactory.newDocumentBuilder();
        InputSource is = new InputSource(new ByteArrayInputStream(baos.toByteArray()));
        return builder.parse(is);
    }
4

1 回答 1

0

DocumentBuilder 默认情况下不支持命名空间。您需要 setNamespaceAware(true)。如果没有命名空间意识,样式表中的模板规则将不匹配,因此默认模板规则会启动,这些只是输出文本节点。

请注意,仅创建一个 DOM 来为 XSLT 提供输入是一个非常糟糕的主意。使用 XSLT 处理器的本机树表示几乎肯定会更好。

于 2013-04-09T07:57:58.827 回答