0

I have an .xml file containing two sets of information that I want to match up to each other based on their ID value (1.2). For example, this snippet.

<rule id="1.2">
      <checker id="checker.id">
         <description locale="en">description</description>
      </checker>
</rule>

<rule id="1.2">
        <checker>
            <category locale="en">Advisory</category>
            <decidable locale="en">Yes</decidable>
        </checker>  
</rule>    

I have a .xsl for each rule, add the values to a table entry

<row>
    <entry>
        <xsl:value-of select="@id"/>                                                                    
    </entry>
    <entry>
        <xsl:for-each select="checker">
        <xsl:value-of select="category[@locale=$locale]"/>
        </xsl:for-each>
    </entry>
    <entry>
        <xsl:for-each select="checker">
        <xsl:value-of select="decidable[@locale=$locale]"/>
        </xsl:for-each>
    </entry>
    <entry>
        <xsl:for-each select="checker">
        <p>
        <codeph>
        <xsl:value-of select="@id"/></codeph><xsl:text>&#160;</xsl:text>
        <xsl:value-of select="description[@locale=$locale]"/>
        </p>
        </xsl:for-each>                                   
    </entry>                                    
</row>  

The current result gives me this, but it has created two separate rows even though the ID is the same. What can I do to have the information with the same ID be in the same row?

<row>
    <entry>1.2</entry>
    <entry>Advisory</entry>
    <entry>Yes</entry>
    <entry>
    <p>
    <codeph/></p>
    </entry>
</row>
<row>
    <entry>1.2</entry>
    <entry/>
    <entry/>
    <entry>
    <p>
    <codeph>checker.id</codeph>description</p>
    </entry>
</row>

Desired outcome:

<row>
    <entry>1.2</entry>
    <entry>Advisory</entry>
    <entry>Yes</entry>
    <entry>
    <p><codeph>checker.id</codeph>description</p>
    </entry>
</row>

1 Answers1

2

This is a variant of the so-called Muenchian grouping.
The following XSLT chooses the first match of the sorted <xsl:key> of all <rule>s and then compiles the desired outcome by matching all <rule>s with the same @id by applying the // operator with a predicate.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:key name="kSorted" match="rule" use="@id" />
  <xsl:variable name="locale" select="'en'" />

    <xsl:template match="/root">
      <xsl:apply-templates select="rule[generate-id() = generate-id(key('kSorted',@id)[1])]">
        <xsl:sort select="@id" />
      </xsl:apply-templates>
    </xsl:template>

    <xsl:template match="rule">
      <xsl:variable name="thisID" select="@id" />
      <row>
        <entry><xsl:value-of select="@id"/></entry>
        <entry><xsl:value-of select="//rule[@id = $thisID]//category[@locale=$locale]"/></entry>
        <entry><xsl:value-of select="//rule[@id = $thisID]//decidable[@locale=$locale]"/></entry>
        <entry>
          <p>
            <codeph><xsl:value-of select="checker/@id"/></codeph><xsl:text>&#160;</xsl:text>
            <xsl:value-of select="checker/*[@locale=$locale][1]"/>
          </p>
        </entry>                                    
      </row> 
    </xsl:template>

</xsl:stylesheet>
Community
  • 1
  • 1
zx485
  • 28,498
  • 28
  • 50
  • 59