我从xml.com
中抽取样本来证明我遇到的问题。
我有这个XML:
<?xml version="1.0"?>
<!--slightly modified source from xml.com -->
<winelist xmlns="urn:somesite:api:base">
<wine grape="Chardonnay">
<winery>Lindeman's</winery>
<product>Bin 65</product>
<year>1998</year>
<prices>
<list>6.99</list>
<discounted>5.99</discounted>
<case>71.50</case>
</prices>
</wine>
<wine grape="Chardonnay">
<winery>Benziger</winery>
<product>Carneros</product>
<year>1997</year>
<prices>
<list>10.99</list>
<discounted>9.50</discounted>
<case>114.00</case>
</prices>
</wine>
<wine grape="Cabernet">
<winery>Duckpond</winery>
<product>Merit Selection</product>
<year>1996</year>
<prices>
<list>13.99</list>
<discounted>11.99</discounted>
<case>143.50</case>
</prices>
</wine>
<wine grape="Chardonnay">
<winery>Kendall Jackson</winery>
<product>Vintner's Reserve</product>
<year>1998</year>
<prices>
<list>12.50</list>
<discounted>9.99</discounted>
<case>115.00</case>
</prices>
</wine>
</winelist>
这个XSL:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="winelist">
<xsl:copy>
<xsl:apply-templates>
<xsl:sort data-type="number" select="prices/discounted"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
我正在尝试按折扣价对wine
元素进行排序,但转换后的XML仍然未排序,除非我先从winelist中删除命名空间(即只使用<winelist>
)。
如何修改XSLT,以便不必手动删除命名空间?
此外,转换后的XML中的wine实体缺少原始的grape
属性。如何保存这些?评论也是如此(不过那么重要)。
我可以先使用另一个转换来删除所有命名空间,但我不太喜欢这个两步解决方案,而且我认为它可能是其他XML源问题的根源。
有人可以帮助我吗?
答案 0 :(得分:0)
您唯一需要做的就是将命名空间添加到XSLT并将match="*"
模板修改为identity transform。
示例:
<xsl:stylesheet xmlns:x="urn:somesite:api:base" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="x:winelist">
<xsl:copy>
<xsl:apply-templates>
<xsl:sort data-type="number" select="x:prices/x:discounted"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
local-name()
如果命名空间未知(使用Xalan和Saxon 6.5.5测试)的示例:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="*[local-name()='winelist']">
<xsl:copy>
<xsl:apply-templates>
<xsl:sort data-type="number" select="*[local-name()='prices']/*[local-name()='discounted']"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
答案 1 :(得分:-1)
首先,要制作输入XML的忠实副本,请使用以下内容(称为“身份转换”):
<xsl:template match="@*|*|processing-instruction()|comment()">
<xsl:copy>
<xsl:apply-templates select="@*|*|text()|processing-instruction()|comment()"/>
</xsl:copy>
</xsl:template>
其次,为了让你的匹配器忽略命名空间(如果那是你真正想要做的),你可以通过local-name匹配:
<xsl:template match="*[local-name()='winelist']">
或者,您可以让您的XSLT知道命名空间并在该命名空间中显式匹配,这是更常用的方法。你不想这样做的唯一原因是你事先不知道命名空间。
<xsl:stylesheet xmlns:w="urn:somesite:api:base">
...
<xsl:template match="w:wine">
...