最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

xml - XSLT 2.0 for-each-group - Stack Overflow

programmeradmin4浏览0评论

I'm trying to understand how works grouping in xslt 2.0. My case: I need to group several documents with identical nodes value. Xml example:

<items>
<item>
    <!-- can be multiple -->
    <doc>
        <doc_root>
            <date>
                <value>
                    <!-- document creation date -->
                </value>
            </date>
            <doc_main_section>
                <data>
                    <info>
                        <!-- can be multiple -->
                        <domain>
                            <!-- can be multiple -->
                            <domain>
                                <value>
                                    <value>d1</value>
                                </value>
                            </domain>
                            <group>
                                <!-- can be multiple -->
                                <group>
                                    <value>
                                        <value>group1</value>
                                    </value>
                                </group>
                                <domain_section>
                                    <!-- can be multiple -->
                                    <domain_section>
                                        <value>
                                            <value>d110</value>
                                        </value>
                                    </domain_section>
                                    <skill>
                                        <!-- can be multiple -->
                                        <skill>
                                            <value>
                                                <value>d1102</value>
                                            </value>
                                        </skill>
                                        <score>
                                            <value>
                                                <magnitude>1.0</magnitude>
                                            </value>
                                        </score>
                                    </skill>
                                </domain_section>
                            </group>
                        </domain>
                    </info>
                </data>
            </doc_main_section>
        </doc_root>
    </doc>
</item>

I tried to group that way:

<xsl:variable name="tableInfo">
            <xsl:for-each select="item">
              <xsl:for-each select="doc/doc_root/doc_main_section/data/info">
                <xsl:for-each-group select="domain" group-by="domain/value/value">
                  <domain>
                    <content>
                      <xsl:value-of select="current-grouping-key()"/>
                    </content>
                    <xsl:for-each-group select="current-group()" group-by="group/group/value/value">
                      <group>
                        <content>
                          <xsl:value-of select="current-grouping-key()"/>
                        </content>
                        <xsl:for-each-group select="current-group()" group-by="domain_section/domain_section/value/value">
                          <domainSection>
                            <content>
                              <xsl:value-of select="current-grouping-key()"/>
                            </content>
                            <xsl:for-each-group select="current-group()" group-by="skill/skill/value/value">
                              <skill>
                                <content>
                                  <xsl:value-of select="current-grouping-key()"/>
                                </content>
                                <xsl:for-each select="score">
                                  <score>
                                    <content>
                                      <xsl:value-of select="value/value"/>
                                    </content>
                                  </score>
                                </xsl:for-each>
                              </skill>
                            </xsl:for-each-group>
                          </domainSection>
                        </xsl:for-each-group>
                      </group>
                    </xsl:for-each-group>
                  </domain>
                </xsl:for-each-group>
              </xsl:for-each>
            </xsl:for-each>
          </xsl:variable>

But I can't see any nodes deeper than group values. Why? And how correct group my nodes before put it in the table?

I thought in that way: at first I group domains in all documents, next - in this domains I group groups, in groups - domain sections and finally I group skills where score values will be in columns by date of docs

After grouping I need to collect unique data in table:

Domain Group Domain section Skill Doc creation date
First group value 1 d section val skill 1 1.0
skill 2 2.0
d section val 2 skill 3 3.0
skill 4 2.0
group value 2 d section val 3 skill 5 5.0
skill 6 1.0
d section val 4 skill 7 2.0
skill 8 4.0

I'm trying to understand how works grouping in xslt 2.0. My case: I need to group several documents with identical nodes value. Xml example:

<items>
<item>
    <!-- can be multiple -->
    <doc>
        <doc_root>
            <date>
                <value>
                    <!-- document creation date -->
                </value>
            </date>
            <doc_main_section>
                <data>
                    <info>
                        <!-- can be multiple -->
                        <domain>
                            <!-- can be multiple -->
                            <domain>
                                <value>
                                    <value>d1</value>
                                </value>
                            </domain>
                            <group>
                                <!-- can be multiple -->
                                <group>
                                    <value>
                                        <value>group1</value>
                                    </value>
                                </group>
                                <domain_section>
                                    <!-- can be multiple -->
                                    <domain_section>
                                        <value>
                                            <value>d110</value>
                                        </value>
                                    </domain_section>
                                    <skill>
                                        <!-- can be multiple -->
                                        <skill>
                                            <value>
                                                <value>d1102</value>
                                            </value>
                                        </skill>
                                        <score>
                                            <value>
                                                <magnitude>1.0</magnitude>
                                            </value>
                                        </score>
                                    </skill>
                                </domain_section>
                            </group>
                        </domain>
                    </info>
                </data>
            </doc_main_section>
        </doc_root>
    </doc>
</item>

I tried to group that way:

<xsl:variable name="tableInfo">
            <xsl:for-each select="item">
              <xsl:for-each select="doc/doc_root/doc_main_section/data/info">
                <xsl:for-each-group select="domain" group-by="domain/value/value">
                  <domain>
                    <content>
                      <xsl:value-of select="current-grouping-key()"/>
                    </content>
                    <xsl:for-each-group select="current-group()" group-by="group/group/value/value">
                      <group>
                        <content>
                          <xsl:value-of select="current-grouping-key()"/>
                        </content>
                        <xsl:for-each-group select="current-group()" group-by="domain_section/domain_section/value/value">
                          <domainSection>
                            <content>
                              <xsl:value-of select="current-grouping-key()"/>
                            </content>
                            <xsl:for-each-group select="current-group()" group-by="skill/skill/value/value">
                              <skill>
                                <content>
                                  <xsl:value-of select="current-grouping-key()"/>
                                </content>
                                <xsl:for-each select="score">
                                  <score>
                                    <content>
                                      <xsl:value-of select="value/value"/>
                                    </content>
                                  </score>
                                </xsl:for-each>
                              </skill>
                            </xsl:for-each-group>
                          </domainSection>
                        </xsl:for-each-group>
                      </group>
                    </xsl:for-each-group>
                  </domain>
                </xsl:for-each-group>
              </xsl:for-each>
            </xsl:for-each>
          </xsl:variable>

But I can't see any nodes deeper than group values. Why? And how correct group my nodes before put it in the table?

I thought in that way: at first I group domains in all documents, next - in this domains I group groups, in groups - domain sections and finally I group skills where score values will be in columns by date of docs

After grouping I need to collect unique data in table:

Domain Group Domain section Skill Doc creation date
First group value 1 d section val skill 1 1.0
skill 2 2.0
d section val 2 skill 3 3.0
skill 4 2.0
group value 2 d section val 3 skill 5 5.0
skill 6 1.0
d section val 4 skill 7 2.0
skill 8 4.0

UPD (expected result after processing in variable):

 <xsl:variable name="tableInfo">
  <domain>
    <content>First</content>
    <group>
      <content>group value 1</content>
      <domainSection>
        <content>d section val</content>
        <skill>
          <content>skill 1</content>
          <score>
            <content>1.0</content>
          </score>
        </skill>
        <skill>
          <content>skill 2</content>
          <score>
            <content>2.0</content>
          </score>
        </skill>
      </domainSection>
      <domainSection>
        <content>d section val 2</content>
        <skill>
          <content>skill 3</content>
          <score>
            <content>3.0</content>
          </score>
        </skill>
        <skill>
          <content>skill 4</content>
          <score>
            <content>2.0</content>
          </score>
        </skill>
      </domainSection>
    </group>
    <group>
      <content>group value 2</content>
      <domainSection>
        <content>d section val 3</content>
        <skill>
          <content>skill 5</content>
          <score>
            <content>5.0</content>
          </score>
        </skill>
        <skill>
          <content>skill 6</content>
          <score>
            <content>1.0</content>
          </score>
        </skill>
      </domainSection>
      <domainSection>
        <content>d section val 4</content>
        <skill>
          <content>skill 7</content>
          <score>
            <content>2.0</content>
          </score>
        </skill>
        <skill>
          <content>skill 8</content>
          <score>
            <content>4.0</content>
          </score>
        </skill>
      </domainSection>
    </group>
  </domain>
</xsl:variable>

I expected in variable would be the data like that. With them I planned to build my table row by row. But with my code it works fine only before I started processing domain_section nodes - I can't see them in my variable (and deeper nodes, like skill and score, too). So I try to understand how works context with current-group() function. In my meaning when I start new for-each group in current-group I take a sub-group from previous step of for-each-group, like:

  <domain>
    <content>First</content>
    <!-- I grouped it at first -->
    <group>
        <content>group 1</content>
        <!-- another nodes -->
    </group>
    <group>
        <content>group 2</content>
        <!-- another nodes -->
    </group>
</domain>

and I thought that in the second for-each-group in current-group() I would work with this context:

    <group>
        <content>group 1</content>
        <!-- another nodes -->
    </group>
    <group>
        <content>group 2</content>
        <!-- another nodes -->
    </group>
Share Improve this question edited Apr 1 at 3:55 Roman G asked Mar 31 at 4:10 Roman GRoman G 11 bronze badge New contributor Roman G is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct. 5
  • What is the target format you are trying to create that result table with? HTML, XSL-FO, Excel, Docbook, something else? – Martin Honnen Commented Mar 31 at 11:30
  • For my case, the result format is HTML – Roman G Commented Mar 31 at 14:01
  • It might help us to understand where your code fails if you post both the result you want to create with the grouping code you have shown and the result you currently get. It is not obviously to me what you refer to with "But I can't see any nodes deeper than group values. Why?". – Martin Honnen Commented Mar 31 at 15:04
  • Also, given that the current version of XSLT is 3.0 and not 2.0, and that all supported of Saxon (e.g. Saxon Java, SaxonC, Saxon .NET, SaxonJS) these days are XSLT 3.0 processors, why is that question tagged as XSLT 2.0? It seems for your multi step processing to group and transform to HTML it might make more sense to use XSLT/XPath 3.1 features like nested arrays of nodes to store intermediary grouping results rather than creating those intermediary XML elements like domain, group. – Martin Honnen Commented Mar 31 at 23:13
  • @MartinHonnen I added expected result to the question's description about grouping. The question tagged as XSLT 2.0 because I work with this version on my project. But your advice is interesting for future plans. Can you share a link where I can learn more about nested arrays in XSLT 3.0? – Roman G Commented Apr 1 at 4:01
Add a comment  | 

2 Answers 2

Reset to default 0

This is an incredibly confusing document structure, with paths like domain/domain/value/value. That doesn't make the task impossible, but it makes it much harder to keep a clear head about exactly what the context is for every path expression. I think you're OK until you get to

<xsl:for-each-group select="current-group()" group-by="domain_section/domain_section/value/value">

which looks wrong to me. The context item here is an outer-level domain element, and this doesn't have a domain-section child.

For the presented input sample (taking the only well-formed item shown there as the input) the code

<xsl:template match="/">
    <xsl:for-each select="item">
      <xsl:for-each select="doc/doc_root/doc_main_section/data/info">
        <xsl:for-each-group select="domain" group-by="domain/value/value">
          <domain>
            <content>
              <xsl:value-of select="current-grouping-key()"/>
            </content>
            <xsl:for-each-group select="current-group()" group-by="group/group/value/value">
              <group>
                <content>
                  <xsl:value-of select="current-grouping-key()"/>
                </content>
                <xsl:for-each-group select="current-group()" group-by="group/domain_section/domain_section/value/value">
                  <domainSection>
                    <content>
                      <xsl:value-of select="current-grouping-key()"/>
                    </content>
                    <xsl:for-each-group select="current-group()" group-by="group/domain_section/skill/skill/value/value">
                      <skill>
                        <content>
                          <xsl:value-of select="current-grouping-key()"/>
                        </content>
                        <xsl:for-each select="group/domain_section/skill/score">
                          <score>
                            <content>
                              <xsl:value-of select="value/magnitude"/>
                            </content>
                          </score>
                        </xsl:for-each>
                      </skill>
                    </xsl:for-each-group>
                  </domainSection>
                </xsl:for-each-group>
              </group>
            </xsl:for-each-group>
          </domain>
        </xsl:for-each-group>
      </xsl:for-each>
    </xsl:for-each>    
  </xsl:template>

output

<domain>
   <content>d1</content>
   <group>
      <content>group1</content>
      <domainSection>
         <content>d110</content>
         <skill>
            <content>d1102</content>
            <score>
               <content>1.0</content>
            </score>
         </skill>
      </domainSection>
   </group>
</domain>
发布评论

评论列表(0)

  1. 暂无评论