Access attribute from within current-grouping-key() xslt

て烟熏妆下的殇ゞ 提交于 2019-12-08 03:00:28

Elaborating on the brief answer given by Martin. Concatenate the string value of writer and a potential differentiator attribute and hand it to for-each-group as the "group-by" value.

Then, two variables $person and $year separate the two parts of the grouping key again. This only solves the problem for writer elements, not for director.

As an aside note, usually IDs cannot contain whitespace. If your id attribute is a "true" ID, you should strip any whitespace in the ID value.

Also, use exclude-prefixes="#all" to prevent unused namespaces from appearing in the output HTML.

Stylesheet

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    exclude-result-prefixes="#all"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:functx="http://www.functx.com" version="2.0">
    <xsl:output method="html" indent="yes"/>

    <xsl:function name="functx:substring-after-last-match" as="xs:string"
        xmlns:functx="http://www.functx.com">
        <xsl:param name="arg" as="xs:string?"/>
        <xsl:param name="regex" as="xs:string"/>

        <xsl:sequence select="
            replace($arg,concat('^.*',$regex),'')
            "/>

    </xsl:function>

    <xsl:template match="mediaList">
        <html>
            <head>
                <link rel="stylesheet" type="text/css" href="CssJs/tableMedia.css"/>
                <title>Media Table</title>
            </head>
            <body>
                <table>
                    <thead>
                        <tr>
                            <th>#</th>
                            <th>Person</th>
                            <th>Movies</th>
                        </tr>
                    </thead>
                    <tbody>
                        <xsl:for-each-group select="movie" group-by="writer/concat(@differentiator, '_', .), director">
                            <xsl:sort
                                select="functx:substring-after-last-match(current-grouping-key(),'\s')"/>
                            <xsl:sort select="current-grouping-key()"/>

                           <xsl:variable name="person" select="if (contains(current-grouping-key(),'_')) then substring-after(current-grouping-key(),'_') else current-grouping-key()"/>
                            <xsl:variable name="year" select="if (contains(current-grouping-key(),'_')) then substring-before(current-grouping-key(),'_') else ''"/>

                            <tr>
                                <td>
                                    <xsl:value-of select="position()"/>
                                </td>
                                <td>
                                    <p>
                                        <a id="{concat(replace($person,' ',''),$year)}">
                                            <xsl:value-of select="if ($year) then concat($person,' (',$year,')') else $person"/>
                                        </a>
                                    </p>
                                </td>
                                <td>
                                    <xsl:if test="current-group()[writer = $person]">
                                        <h3>Writer</h3>
                                    </xsl:if>
                                    <xsl:apply-templates
                                        select="current-group()[writer = $person]/title[not(@type)]"/>
                                    <xsl:if test="current-group()[director = $person]">
                                        <h3>Director</h3>
                                    </xsl:if>
                                    <xsl:apply-templates
                                        select="current-group()[director = $person]/title[not(@type)]"
                                    />
                                </td>
                            </tr>
                        </xsl:for-each-group>
                    </tbody>
                </table>
            </body>
        </html>
    </xsl:template>

    <xsl:template match="title">
        <p>
            <xsl:value-of select="."/>
            <xsl:apply-templates select="../title[@type]"/>
        </p>
    </xsl:template>

    <xsl:template match="title[@type]">
        <span>
            <xsl:value-of select="concat(' (',.,')')"/>
        </span>
    </xsl:template>            
</xsl:stylesheet>

XML Input

I used the following input, with more than one movie written by Thomas Lennon (1970).

<mediaList>
        <movie id="1603934" dateCreated="2014-08-11">
          <title>Night at the Museum</title>
          <director>Shawn Levy</director>
          <LCSpecialTopics>Comedy</LCSpecialTopics>
          <writer>Robert Ben Garant</writer>
          <writer differentiator="1970">Thomas Lennon</writer>
          <language>English</language>
          <year>2006</year>
       </movie>
        <movie id="1603934" dateCreated="2014-08-11">
          <title>Second movie</title>
          <director>Frodo Baggins</director>
          <LCSpecialTopics>Comedy</LCSpecialTopics>
          <writer differentiator="1970">Thomas Lennon</writer>
          <language>English</language>
          <year>2006</year>
       </movie>

      <movie lastModified="2014-08-30" id="1123629" dateCreated="2014-08-04">
          <title type="foreign" xml:lang="cmn">Qiúgǎng Wèishì</title>
          <title>Warriors of Qiugang</title>
          <director>Ruby Yang</director>
          <LCSpecialTopics>Documentary films</LCSpecialTopics>
          <writer differentiator="1951">Thomas Lennon</writer>
          <language>Chinese</language>
          <year>2010</year>
       </movie>
</mediaList>

XML Output

<html>
   <head>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      <link rel="stylesheet" type="text/css" href="CssJs/tableMedia.css">
      <title>Media Table</title>
   </head>
   <body>
      <table>
         <thead>
            <tr>
               <th>#</th>
               <th>Person</th>
               <th>Movies</th>
            </tr>
         </thead>
         <tbody>
            <tr>
               <td>1</td>
               <td>
                  <p><a id="FrodoBaggins">Frodo Baggins</a></p>
               </td>
               <td>
                  <h3>Director</h3>
                  <p>Second movie</p>
               </td>
            </tr>
            <tr>
               <td>2</td>
               <td>
                  <p><a id="RobertBenGarant">Robert Ben Garant</a></p>
               </td>
               <td>
                  <h3>Writer</h3>
                  <p>Night at the Museum</p>
               </td>
            </tr>
            <tr>
               <td>3</td>
               <td>
                  <p><a id="ThomasLennon1951">Thomas Lennon (1951)</a></p>
               </td>
               <td>
                  <h3>Writer</h3>
                  <p>Warriors of Qiugang<span> (Qiúgǎng Wèishì)</span></p>
               </td>
            </tr>
            <tr>
               <td>4</td>
               <td>
                  <p><a id="ThomasLennon1970">Thomas Lennon (1970)</a></p>
               </td>
               <td>
                  <h3>Writer</h3>
                  <p>Night at the Museum</p>
                  <p>Second movie</p>
               </td>
            </tr>
            <tr>
               <td>5</td>
               <td>
                  <p><a id="ShawnLevy">Shawn Levy</a></p>
               </td>
               <td>
                  <h3>Director</h3>
                  <p>Night at the Museum</p>
               </td>
            </tr>
            <tr>
               <td>6</td>
               <td>
                  <p><a id="RubyYang">Ruby Yang</a></p>
               </td>
               <td>
                  <h3>Director</h3>
                  <p>Warriors of Qiugang<span> (Qiúgǎng Wèishì)</span></p>
               </td>
            </tr>
         </tbody>
      </table>
   </body>
</html>

EDIT As a response to your comment:

What IS that comma doing though in the group-by rather than a |?

That's an excellent follow-up question! The | operator returns the union of two sets of nodes, with duplicates removed and in document order. Its operands must necessarily be sets of nodes. But the first part of your group-by value is not a set of nodes, it's just a string (the concat() function returns a string). On the other hand, the operands of the comma operator , can be any kind of sequences, also ones of type xs:string.

In short, you have to use , rather than | because of the kinds of operands those operators accept. It has no bearing on the grouping whatsoever. When all sequences that contribute to the grouping key are sets of nodes, the two operators can be used interchangeably, save for potential changes in ordering.

You can use group-by="writer/concat(@differentiator, '+', .), director".

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!