2015-10-09 17 views
0

我一直在四處尋找Java示例以使用XSLT轉換XML文檔。我發現了幾個使用new File("path/to/file.xml")的樣本來加載XML和XSLT,並且這些樣本很好。我的問題是,我試圖用一種新的方法來使用這個方法,它將接受兩個org.w3c.dom.Document對象。只要將用於加載XSLT的StreamSource替換爲DOMSource,我的調用結果就是XSLT,而不是轉換的XML。從How to call XSL template from java code?使用DOM在Java中使用XSLT轉換XML

工作代碼:

Source xmlInput = new StreamSource(new File("c:/path/to/input.xml")); 
Source xsl = new StreamSource(new File("c:/path/to/file.xsl")); 
Result xmlOutput = new StreamResult(new File("c:/path/to/output.xml")); 

try { 
    Transformer transformer =  TransformerFactory.newInstance().newTransformer(xsl); 
    transformer.transform(xmlInput, xmlOutput); 
} catch (TransformerException e) { 
    // Handle. 
} 

我的代碼:

public static Document transformXML(Document xml, Document xslt) throws TransformerException, UnsupportedEncodingException, SAXException, IOException, ParserConfigurationException, FactoryConfigurationError{ 

    Source xmlSource = new DOMSource(xml); 
    Source xsltSource = new DOMSource(xslt); 
    StreamResult result = new StreamResult(new StringWriter()); 

    // the factory pattern supports different XSLT processors 
    TransformerFactory transFact = 
      TransformerFactory.newInstance(); 
    Transformer trans = transFact.newTransformer(xsltSource); 

    trans.transform(xmlSource, result); 

    Document resultDoc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new ByteArrayInputStream(result.getWriter().toString().getBytes("utf-8"))); 

    return resultDoc; 
} 

我的結果文件,則XSLT,而不是XML。我在做什麼錯了DOMSource

+0

您是否向使用名稱空間感知文檔生成器構建的變換器提供的DOM樹?如果你想要一個'Document'節點作爲結果,爲什麼不直接使用'DOMResult result = new DOMResult(); trans.transform(xmlSource,result); Document resultDoc =(Document)result.getNode();'? –

+0

@MartinHonnen非常好的一點。我更新了代碼。現在出於某種可怕的原因,我的resultDoc仍然是XSLT。這就像變壓器_switches_他們了!? – GuillaumeC91

回答

0

XSLT和XPath只有在感知名稱空間的DOM實現和DOM樹時纔有意義,這就是爲什麼我問「爲使用名稱空間感知文檔生成器構建的變換器提供的DOM樹是否是?在我的評論中。

就我測試過的Oracle Java 1.8而言,如果使用了不支持名稱空間的DocumentBuilderFactory和內置的Transformer,那麼您的方法將返回樣式表代碼。但是,只要我將DocumentBuilderFactory更改爲可識別名稱空間,結果就像預期的那樣。

下面是工作樣品:

package domsourcetest1; 

import java.io.IOException; 
import javax.xml.parsers.FactoryConfigurationError; 
import javax.xml.parsers.ParserConfigurationException; 
import javax.xml.transform.Source; 
import javax.xml.transform.Transformer; 
import javax.xml.transform.TransformerException; 
import javax.xml.transform.TransformerFactory; 
import javax.xml.transform.dom.DOMResult; 
import javax.xml.transform.dom.DOMSource; 
import org.w3c.dom.Document; 
import javax.xml.parsers.DocumentBuilderFactory; 
import javax.xml.parsers.DocumentBuilder; 
import org.xml.sax.SAXException; 
import org.w3c.dom.DOMImplementation; 
import org.w3c.dom.ls.DOMImplementationLS; 
import org.w3c.dom.ls.LSSerializer; 

/** 
* 
* @author Martin Honnen 
*/ 
public class DOMSourceTest1 { 


    public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException, TransformerException { 
     DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 
     dbf.setNamespaceAware(true); 
     DocumentBuilder db = dbf.newDocumentBuilder(); 
     Document xslt = db.parse("sheet1.xsl"); 
     Document xml = db.newDocument(); 
     xml.appendChild(xml.createElementNS(null, "root")); 
     Document result = transformXML(xml, xslt); 
     System.out.println(result.getDocumentElement().getTextContent()); 
     LSSerializer serializer = ((DOMImplementationLS) xml.getImplementation()).createLSSerializer(); 
     System.out.println(serializer.writeToString(result)); 
    } 

    public static Document transformXML(Document xml, Document xslt) throws TransformerException, ParserConfigurationException, FactoryConfigurationError { 

     Source xmlSource = new DOMSource(xml); 
     Source xsltSource = new DOMSource(xslt); 
     DOMResult result = new DOMResult(); 

     // the factory pattern supports different XSLT processors 
     TransformerFactory transFact 
       = TransformerFactory.newInstance(); 
     Transformer trans = transFact.newTransformer(xsltSource); 

     trans.transform(xmlSource, result); 

     Document resultDoc = (Document) result.getNode(); 

     return resultDoc; 
    } 
} 

的示例樣式表簡單地輸出關於XSLT處理器信息:

程序的
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
    <xsl:template match="/"> 
     <debug> 
      <xsl:value-of select="system-property('xsl:vendor')"/> 
     </debug> 
    </xsl:template> 

</xsl:stylesheet> 

輸出是

Apache Software Foundation (Xalan XSLTC) 
<?xml version="1.0" encoding="UTF-16"?> 
<debug>Apache Software Foundation (Xalan XSLTC)</debug> 

現在,當我在main方法中註釋掉//dbf.setNamespaceAware(true);結果是

<?xml version="1.0" encoding="UTF-16"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:template match="/"><debug><xsl:value-of select="system-property('xsl:vendor')"/></debug></xsl:template></xsl:stylesheet> 

這意味着結果確實是樣式表文件。當我將Saxon 6.5.5放在課程路徑上時,問題不會發生,而在類路徑中的Saxon 9.6也不會發生,這顯然是一個錯誤或者至少是內置Xalan Transformer的一個怪癖。

但是,通常情況下,如果使用XSLT或XPath而不使用名稱空間感知的DOM樹,我不認爲您會得到有意義的結果。另請參閱Xalan版本http://svn.apache.org/viewvc/xalan/java/tags/xalan-j_2_7_2/samples/DOM2DOM/DOM2DOM.java?revision=1695338&view=markup中的DOM2DOM示例,其中說

// And setNamespaceAware, which is required when parsing xsl files 
    dFactory.setNamespaceAware(true); 
+0

你先生真棒! 'dFactory.setNamespaceAware(true);'確實是我所需要的。這是非常有趣的行爲,但我不會與之對抗。 @MartinHonnen – GuillaumeC91