2013-02-13 84 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