XSLT有一个很好的过滤方法

时间:2012-04-30 15:51:37

标签: xml xslt filter

我正在尝试过滤一个记录集,我已经让它可以使用以下XSLT,但它看起来并不好看:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:r="http://www.castiron.com/response" exclude-result-prefixes="r">
    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="/">
        <xsl:element name="Response">
            <xsl:element name="rcode">
                <xsl:text>0</xsl:text>
            </xsl:element>
            <xsl:element name="rmesage">
                <xsl:text>0</xsl:text>
            </xsl:element>
            <xsl:element name="payload">

                <xsl:for-each select="Response/payload/globalBuy[season='A09']">

                    <xsl:element name="season"><xsl:value-of select="season"/></xsl:element>
                    <xsl:element name="productId"><xsl:value-of select="productId"/></xsl:element>
                    <xsl:element name="globalBuyFlag"><xsl:value-of select="globalBuyFlag"/></xsl:element>

                </xsl:for-each>

            </xsl:element>
        </xsl:element>

    </xsl:template>

</xsl:stylesheet>

此外,我发现在根目录中弹出命名空间时会出现问题。以下示例XML:

<?xml version="1.0" encoding="UTF8"?>
<Response xmlns="http://www.castiron.com/response">
    <payload>
        <globalBuy>
            <season>CD12</season>
            <productId>123456</productId>
            <globalBuyFlag>XXL</globalBuyFlag>
        </globalBuy>
    </payload>
</Response>

2 个答案:

答案 0 :(得分:2)

您可以通过删除 xsl:element 的所有用途来简化您的代码。除非您希望动态生成元素名称,否则将元素写为普通XML非常简单。所以不要写这个....

<xsl:element name="rcode">
    <xsl:text>0</xsl:text>
</xsl:element> 

写这个......

<rcode>0</rcode>

对于过滤,如果您要做的只是复制XML,但只包含与过滤器匹配的某些项目,那么您可以覆盖标识模板,并使模板匹配您不<的项目/ strong>想要包含,只是忽略它们。

试试这个简化的XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>

   <xsl:template match="/Response">
      <xsl:copy>
         <xsl:apply-templates select="@*" />
         <rcode>0</rcode>
         <rmesage>0</rmesage>
         <xsl:apply-templates select="node()"/>
      </xsl:copy>
   </xsl:template>

   <xsl:template match="globalBuy[not(season='A09')]" />

   <xsl:template match="@*|node()">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>   
</xsl:stylesheet>

应用于以下XML

<Response>
   <payload>
      <globalBuy>
         <season>CD12</season>
         <productId>123456</productId>
         <globalBuyFlag>XXL</globalBuyFlag>
      </globalBuy>
      <globalBuy>
         <season>A09</season>
         <productId>123456b</productId>
         <globalBuyFlag>XXLb</globalBuyFlag>
      </globalBuy>
   </payload>
</Response>

然后输出以下内容

<Response>
   <rcode>0</rcode>
   <rmesage>0</rmesage>
   <payload>
      <globalBuy>
         <season>A09</season>
         <productId>123456b</productId>
      <globalBuyFlag>XXLb</globalBuyFlag>
   </globalBuy>
   </payload>
</Response>

请注意,我删除了此示例中的所有命名空间,以简化操作。

编辑:如果您确实想要处理默认命名空间,那么在XSLT 1.0中,您将明确指出您匹配的每个元素的命名空间。你会做这样的事情:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:r="http://www.castiron.com/response" exclude-result-prefixes="r">
   <xsl:output method="xml" indent="yes"/>

   <xsl:template match="/r:Response">
      <xsl:copy>
         <rcode xmlns="http://www.castiron.com/response">0</rcode>
         <rmesage xmlns="http://www.castiron.com/response">0</rmesage>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>

   <xsl:template match="r:globalBuy[not(r:season='A09')]" />

   <xsl:template match="@*|node()">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>   
</xsl:stylesheet>

答案 1 :(得分:2)

美丽在旁观者的眼中;我不确定你的代码的哪个方面你找不到漂亮的东西。但我会从这样重写:

    

<xsl:template match="/">
    <Response>
        <rcode>0</rcode>
        <rmesage>0</rmesage>
        <payload>
            <xsl:copy-of select="Response/payload/globalBuy[season='A09']/
                                    (season, productId, globalBuyFlag)">
        </payload>
    </Response>

</xsl:template>

xsl:copy-of表达式使用XPath 2.0;如果你想要一个XSLT 1.0解决方案,你必须把xsl:for-each放回去。

关于命名空间,只需谷歌搜索“XSLT默认命名空间”,你就会找到一百万个帖子来解释你的错误。