Java XML转换 - 奇怪的问题

时间:2013-04-08 23:35:53

标签: java xml xslt transform

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

以下是我的方法:

这个没有错误地工作并产生正确的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,以下内容生成仅包含Text节点的XML(或来自XML的内容)(无元素,属性等)

    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,但这看起来有点像hacky。有关为什么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);
    }

1 个答案:

答案 0 :(得分:0)

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

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