2013-02-13 82 views
3

我試圖解析一個很簡單的例子:javax.xml.transform.Transformer忽略前綴?

<?xml version="1.0" encoding="UTF-8"?> 
<root xmlns:openSearch='http://a9.com/-/spec/opensearch/1.1/'> 
    <openSearch:totalResults>100</openSearch:totalResults> 
</root> 

我使用的樣式表如下:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
       version="1.0" 
       xmlns:app='http://www.w3.org/2007/app' > 
<xsl:output method="xml" indent="yes"/> 
<xsl:preserve-space elements="*"/> 
<xsl:template match="/"> 
    <results> 
     <xsl:attribute name="total-results"> 
       <xsl:value-of 
       select="atom:root/openSearch:totalResults"/> 
     </xsl:attribute> 
    </results> 
</xsl:template> 
</xsl:stylesheet> 

這工作在的libxslt,沒有問題。我正試圖在java中執行相同的任務,並且正在嘗試使用javax.xml.transform包來執行此操作。它不是預期的結果,它爲總結果屬性提供了一個空值。但是,當我改變這個值:

   <xsl:value-of select="root/totalResults"/> 

它的工作原理。更改xml和xslt不是一個選項。有一個參數我應該設置在某個地方?代碼非常簡單:

InputSource xmlSource = new InputSource(new StringReader(xml)); 

DocumentBuilder builder = factory.newDocumentBuilder(); 
document = builder.parse(xmlSource); 

// Use a Transformer for output 
TransformerFactory tFactory = TransformerFactory.newInstance(); 


StreamSource stylesource = new StreamSource(new StringReader(styleSheet)); 
Transformer transformer = tFactory.newTransformer(stylesource); 

StringWriter writer = new StringWriter(); 

DOMSource source = new DOMSource(document); 
StreamResult result = new StreamResult(writer); 
transformer.transform(source, result); 

stringResult = writer.toString(); 
+1

你說改變XSLT不是一種選擇,但是XSLT是錯誤的。您正在使用兩個未定義的名稱空間前綴,並且其中一個前綴不應存在。 – JLRishe 2013-02-13 09:07:37

+1

我無法重現您描述的行爲:xsltproc不接受您提供的樣式表,但由於未定義前綴而引發命名空間錯誤。你想要儘可能小的例子來說明行爲 - 但不是更小的! – 2013-02-13 15:47:41

+0

你說得對。我的問題最終出現在Java代碼中(請參閱接受的答案),但在將來發布代碼時我會更加小心。 – user1532390 2013-02-13 18:31:31

回答

5

在樣式表中,您缺少「atom」和「openSearch」的名稱空間聲明。 以下工作:

  1. 添加了「OpenSearch的」命名空間(從XML複製)在樣式表
  2. 刪除了「原子」命名空間,因爲有
  3. 將工廠作爲本 名字空間中沒有信息命名空間意識到:factory.setNamespaceAware(true);

這裏是Scala的完整代碼(對不起,我是懶得解析該文件中的XML和樣式表或在Java中做字符串連接):

def testxsl = { 
     val xml = """<?xml version="1.0" encoding="UTF-8"?> 
<root xmlns:openSearch='http://a9.com/-/spec/opensearch/1.1/'> 
    <openSearch:totalResults>100</openSearch:totalResults> 
</root> 
     """ 
     val styleSheet = """<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" 
     xmlns:app='http://www.w3.org/2007/app' 
     xmlns:openSearch='http://a9.com/-/spec/opensearch/1.1/'> 
<xsl:output method="xml" indent="yes"/> 
<xsl:preserve-space elements="*"/> 
<xsl:template match="/"> 
    <results> 
     <xsl:attribute name="total-results"> 
       <xsl:value-of select="root/openSearch:totalResults"/> 
     </xsl:attribute> 
    </results> 
</xsl:template> 
</xsl:stylesheet> 
     """ 
    val xmlSource = new InputSource(new StringReader(xml)); 
    val factory = DocumentBuilderFactory.newInstance(); 
    factory.setNamespaceAware(true); 
    val builder = factory.newDocumentBuilder(); 
    val document = builder.parse(xmlSource); 

    // Use a Transformer for output 
    val tFactory = TransformerFactory.newInstance(); 


    val stylesource = new StreamSource(new StringReader(styleSheet)); 
    val transformer = tFactory.newTransformer(stylesource); 

    val writer = new StringWriter(); 

    val source = new DOMSource(document); 
    val result = new StreamResult(writer); 
    transformer.transform(source, result); 
    writer.toString(); 
    } 
+1

針對第3點的+1 - 很容易忘記默認情況下「DocumentBuilderFactory」不是_名稱空間。 – 2013-02-13 15:58:26

+1

但是,除非您有非常好的理由,否則不要將工廠更改爲名稱空間感知,請不要將該值作爲DOMSource提供。提供StreamSource並讓XSLT處理器以自己喜歡的內部格式構建樹,這可能比使用DOM快得多。 – 2013-02-13 16:23:30

+0

DocumentBuilderFactory命名空間設置正是我感到困惑的地方。一旦我指向這個方向,我就能夠解決這個問題。 – user1532390 2013-02-13 18:28:50