我需要在运行时在XSLT样式表中设置命名空间。 这是我的XSL:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:tdns="{$myNS}">
<xsl:output method="xml" encoding="iso-8859-1" />
<xsl:param name="myNS" required="yes" />
<xsl:template match="*">
<xsl:choose>
<xsl:when test="name(.)='bugs'">
<xsl:element name="tdns:bugs">
<xsl:for-each select="*">
<xsl:apply-templates select="." />
</xsl:for-each>
</xsl:element>
</xsl:when>
<xsl:when test="name(.)='bug'">
<xsl:element name="tdns:bug">
<xsl:for-each select="*">
<xsl:choose>
<xsl:when test="name(.)='Device' ">
<xsl:choose>
<xsl:when test="string-length(../tdns:Device_Tmp) > 0 ">
<xsl:element name="tdns:Device">
<xsl:value-of select="../tdns:Device_Tmp" />
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:element name="tdns:Device">
<xsl:value-of select="." />
</xsl:element>
</xsl:otherwise>
</xsl:choose>
<xsl:element name="tdns:ShowParamValue">
<xsl:value-of select="$myNS" />
</xsl:element>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</xsl:element>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
输入XML
<?xml version="1.0" encoding="ISO-8859-1"?>
<bugs xmlns="http://my.com">
<bug>
<Device>
<![CDATA[Dev1]]>
</Device>
<Device_Tmp>
<![CDATA[Dev_tmp1]]>
</Device_Tmp>
</bug>
</bugs>
Java代码
TransformerFactory tfactory = TransformerFactory.newInstance();
Transformer transformer = tfactory.newTransformer(new StreamSource(
new File(xsl)));
transformer.setParameter("myNS", "http://my.com");
transformer.transform(new StreamSource(new File(
xml)),
new StreamResult(System.out));
输出XML
<?xml version="1.0" encoding="iso-8859-1"?>
<tdns:bugs xmlns:tdns="http://my.com">
<tdns:bug>
<tdns:Device>
Dev1
</tdns:Device>
<tdns:ShowParamValue>http://my.com</tdns:ShowParamValue>
</tdns:bug>
</tdns:bugs>
如您所见,XSLT不知道任何../tdns:Device_Tmp
节点,但如果我设置了静态命名空间:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:tdns="http://my.com">
...
然后,结果是OK:
<?xml version="1.0" encoding="iso-8859-1"?>
<tdns:bugs xmlns:tdns="http://my.com">
<tdns:bug>
<tdns:Device>
Dev_tmp1
</tdns:Device>
<tdns:ShowParamValue>http://my.com</tdns:ShowParamValue>
</tdns:bug>
</tdns:bugs>
请告诉我我做错了什么。
答案 0 :(得分:1)
命名空间声明不是属性,并且不被视为属性值模板(实际上它们由解析样式表文档的XML解析器处理,然后才能到达XSLT处理器附近)。
您必须使用<xsl:element>
创建具有name
和namespace
属性的元素,以便能够动态指定命名空间。为了匹配元素,最简单的方法可能是完全忽略命名空间(因为你在XSLT 2.0中,*:localname
)很容易。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="iso-8859-1" />
<xsl:param name="myNS" required="yes" />
<!-- this will cover most things, including a Device that doesn't have a
sibling Device_Tmp -->
<xsl:template match="*">
<xsl:element name="tdns:{local-name()}" namespace="{$myNS}">
<xsl:apply-templates />
</xsl:element>
</xsl:template>
<!-- delete Device_Tmp -->
<xsl:template match="*:Device_Tmp" />
<!-- special case for Device elements that have a non-empty sibling
Device_Tmp -->
<xsl:template match="*:Device[string-length(../*:Device_Tmp) > 0]"
priority="2">
<xsl:element name="tdns:{local-name()}" namespace="{$myNS}">
<xsl:value-of select="../*:Device_Tmp" />
</xsl:element>
</xsl:template>
<!-- add debugging element to bug -->
<xsl:template match="*:bug">
<xsl:element name="tdns:{local-name()}" namespace="{$myNS}">
<xsl:apply-templates />
<xsl:element name="tdns:ShowParamValue" namespace="{$myNS}">
<xsl:value-of select="$myNS" />
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
答案 1 :(得分:0)
看起来输入节点不在http://my.com命名空间中。你可以看到这个,因为name(。)='bugs'似乎返回true。 name()函数返回一个扩展的QName,它应该包含命名空间(而不是local-name())。
我不确定为什么会出现这种情况,但也尝试在输入xml中使用前缀。