带计数的 XSLT 转换

发布于 2024-07-25 22:50:40 字数 545 浏览 2 评论 0原文

我如何使用 xslt 将以下内容转换

<blogger>
  <post>
    <text>...</text>
    <categories>Engineering, Internet, Sausages</catgories>
  </post>
  <post>
    <text>...</text>
    <categories>Internet, Sausages</catgories>
  </post>
  <post>
     <text>...</text>
     <categories>Sausages</catgories>
  </post>
</blogger>

   Sausages (3)
   Internet (2)
   Engineering (1)

How would I convert the following using xslt

<blogger>
  <post>
    <text>...</text>
    <categories>Engineering, Internet, Sausages</catgories>
  </post>
  <post>
    <text>...</text>
    <categories>Internet, Sausages</catgories>
  </post>
  <post>
     <text>...</text>
     <categories>Sausages</catgories>
  </post>
</blogger>

into

   Sausages (3)
   Internet (2)
   Engineering (1)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

凉栀 2024-08-01 22:50:40

首先,更改您的 xml

创建 data.xml

<blogger>
 <post>
     <text>...</text>
     <categories>
       <category>Engineering</category>
       <category>Internet</category>
       <category>Sausages</category>
     </categories>          
</post>
 <post>
     <text>...</text>
      <categories>
       <category>Internet</category>
       <category>Sausages</category>
      </categories>     
  </post>
 <post>
     <text>...</text>
     <categories>
      <category>Sausages</category>
     </categories>
 </post>
</blogger>

然后编写你的xslt,创建transform.xslt

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" 
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>

<xsl:template match="/">

  <xsl:for-each select="//category">
   <xsl:variable name="value" select="."/>
   <xsl:if test="count(preceding::category[.=$value]) = 0">
    <xsl:value-of select="."/>
    <xsl:text> (</xsl:text>
    <xsl:value-of select="count(//category[.=$value])"/>     
    <xsl:text>)</xsl:text><br/>
   </xsl:if>
 </xsl:for-each>

 </xsl:template>
</xsl:stylesheet>

然后你可以在Internet Explorer中打开data.xml并得到以下结果:

Engineering (1)Internet (2)Sausages (3)

First, change your xml

create data.xml

<blogger>
 <post>
     <text>...</text>
     <categories>
       <category>Engineering</category>
       <category>Internet</category>
       <category>Sausages</category>
     </categories>          
</post>
 <post>
     <text>...</text>
      <categories>
       <category>Internet</category>
       <category>Sausages</category>
      </categories>     
  </post>
 <post>
     <text>...</text>
     <categories>
      <category>Sausages</category>
     </categories>
 </post>
</blogger>

Then write your xslt, create transform.xslt

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" 
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>

<xsl:template match="/">

  <xsl:for-each select="//category">
   <xsl:variable name="value" select="."/>
   <xsl:if test="count(preceding::category[.=$value]) = 0">
    <xsl:value-of select="."/>
    <xsl:text> (</xsl:text>
    <xsl:value-of select="count(//category[.=$value])"/>     
    <xsl:text>)</xsl:text><br/>
   </xsl:if>
 </xsl:for-each>

 </xsl:template>
</xsl:stylesheet>

Then you can open data.xml in internet explorer and get the following result:

Engineering (1)Internet (2)Sausages (3)
愛上了 2024-08-01 22:50:40

您需要的是:

<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>

  <xsl:template match="/">
    <items>
      <xsl:apply-templates select="/blogger/post/categories" />
    </items>
  </xsl:template>

  <xsl:template match="categories">
    <xsl:call-template name="split">
      <xsl:with-param name="pString" select="." />
    </xsl:call-template>
  </xsl:template>

  <!-- this splits a comma-delimited string into a series of <item>s -->
  <xsl:template name="split">
    <xsl:param name="pString" select="''" />

    <xsl:variable name="vList" select="
      concat($pString, ',')
    " />
    <xsl:variable name="vHead" select="
      normalize-space(substring-before($vList ,','))
    " />
    <xsl:variable name="vTail" select="
      normalize-space(substring-after($vList ,','))
    " />

    <xsl:if test="not($vHead = '')">
      <item>
        <xsl:value-of select="$vHead" />
      </item>
      <xsl:call-template name="split">
        <xsl:with-param name="pString" select="$vTail" />
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>

产生中间结果:

<items>
  <item>Engineering</item>
  <item>Internet</item>
  <item>Sausages</item>
  <item>Internet</item>
  <item>Sausages</item>
  <item>Sausages</item>
</items>

以及:

<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>

  <xsl:output method="text" />
  <xsl:key name="kItem" match="item" use="." />

  <xsl:template match="/items">
    <xsl:apply-templates select="item">
      <xsl:sort 
        select="count(key('kItem', .))" 
        data-type="number" 
        order="descending"
      />
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="item">
    <xsl:if test="
      generate-id() = generate-id(key('kItem', .)[1])
    ">
      <xsl:value-of select="
        concat(
          ., ' (', count(key('kItem', .)), ')
'
        )
      " />
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>

输出:

Sausages (3)
Internet (2)
Engineering (1)

What you need is this:

<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>

  <xsl:template match="/">
    <items>
      <xsl:apply-templates select="/blogger/post/categories" />
    </items>
  </xsl:template>

  <xsl:template match="categories">
    <xsl:call-template name="split">
      <xsl:with-param name="pString" select="." />
    </xsl:call-template>
  </xsl:template>

  <!-- this splits a comma-delimited string into a series of <item>s -->
  <xsl:template name="split">
    <xsl:param name="pString" select="''" />

    <xsl:variable name="vList" select="
      concat($pString, ',')
    " />
    <xsl:variable name="vHead" select="
      normalize-space(substring-before($vList ,','))
    " />
    <xsl:variable name="vTail" select="
      normalize-space(substring-after($vList ,','))
    " />

    <xsl:if test="not($vHead = '')">
      <item>
        <xsl:value-of select="$vHead" />
      </item>
      <xsl:call-template name="split">
        <xsl:with-param name="pString" select="$vTail" />
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>

Which produces this intermediary result:

<items>
  <item>Engineering</item>
  <item>Internet</item>
  <item>Sausages</item>
  <item>Internet</item>
  <item>Sausages</item>
  <item>Sausages</item>
</items>

And this:

<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>

  <xsl:output method="text" />
  <xsl:key name="kItem" match="item" use="." />

  <xsl:template match="/items">
    <xsl:apply-templates select="item">
      <xsl:sort 
        select="count(key('kItem', .))" 
        data-type="number" 
        order="descending"
      />
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="item">
    <xsl:if test="
      generate-id() = generate-id(key('kItem', .)[1])
    ">
      <xsl:value-of select="
        concat(
          ., ' (', count(key('kItem', .)), ')
'
        )
      " />
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>

Which outputs:

Sausages (3)
Internet (2)
Engineering (1)
明媚如初 2024-08-01 22:50:40

其实是可以做到的,而且也不难。 这将实现您想要的功能:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="fo msxsl">
  <xsl:output encoding="UTF-8" indent="yes" method="xml"/>
  <xsl:variable name="Separator">,</xsl:variable>
  <xsl:template match="/">
    <xsl:variable name="NodeList">
      <xsl:apply-templates select="//categories"/>
    </xsl:variable>
    <xsl:variable name="Nodes" select="msxsl:node-set($NodeList)"/>
    <html>
      <head>
        <title>Simple list</title>
      </head>
      <body>
        <xsl:for-each select="$Nodes/Value">
          <xsl:variable name="value" select="."/>
          <xsl:if test="count(preceding::Value[.=$value]) = 0">
            <xsl:value-of select="."/> (<xsl:value-of select="count($Nodes/Value[.=$value])"/>)<br/>
          </xsl:if>
        </xsl:for-each>
      </body>
    </html>
  </xsl:template>
  <xsl:template match="categories" name="Whole">
    <xsl:call-template name="Substring">
      <xsl:with-param name="Value" select="normalize-space(.)"/>
    </xsl:call-template>
  </xsl:template>
  <xsl:template name="Substring">
    <xsl:param name="Value"/>
    <xsl:choose>
      <xsl:when test="contains($Value, $Separator)">
        <xsl:variable name="Before" select="normalize-space(substring-before($Value, $Separator))"/>
        <xsl:variable name="After" select="normalize-space(substring-after($Value, $Separator))"/>
        <Value>
          <xsl:value-of select="$Before"/>
        </Value>
        <xsl:call-template name="Substring">
          <xsl:with-param name="Value" select="$After"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <Value>
          <xsl:value-of select="$Value"/>
        </Value>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

实际上,这是小菜一碟。 :-)

Actually, it can be done and isn't difficult either. This will do what you want it to do:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="fo msxsl">
  <xsl:output encoding="UTF-8" indent="yes" method="xml"/>
  <xsl:variable name="Separator">,</xsl:variable>
  <xsl:template match="/">
    <xsl:variable name="NodeList">
      <xsl:apply-templates select="//categories"/>
    </xsl:variable>
    <xsl:variable name="Nodes" select="msxsl:node-set($NodeList)"/>
    <html>
      <head>
        <title>Simple list</title>
      </head>
      <body>
        <xsl:for-each select="$Nodes/Value">
          <xsl:variable name="value" select="."/>
          <xsl:if test="count(preceding::Value[.=$value]) = 0">
            <xsl:value-of select="."/> (<xsl:value-of select="count($Nodes/Value[.=$value])"/>)<br/>
          </xsl:if>
        </xsl:for-each>
      </body>
    </html>
  </xsl:template>
  <xsl:template match="categories" name="Whole">
    <xsl:call-template name="Substring">
      <xsl:with-param name="Value" select="normalize-space(.)"/>
    </xsl:call-template>
  </xsl:template>
  <xsl:template name="Substring">
    <xsl:param name="Value"/>
    <xsl:choose>
      <xsl:when test="contains($Value, $Separator)">
        <xsl:variable name="Before" select="normalize-space(substring-before($Value, $Separator))"/>
        <xsl:variable name="After" select="normalize-space(substring-after($Value, $Separator))"/>
        <Value>
          <xsl:value-of select="$Before"/>
        </Value>
        <xsl:call-template name="Substring">
          <xsl:with-param name="Value" select="$After"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <Value>
          <xsl:value-of select="$Value"/>
        </Value>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

Actually, it's a piece of cake. :-)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文