0
votes

I have XML like This

<root>
  <Users groupid="1">
    <User id="person1" name="ABC"  parentid="person7"/>
    <User id="person2" name="xyz"  parentid="person1"/>
    <User id="person3" name="LMN"  parentid="bac3"/>
    <User id="person4" name="PQR"  parentid="person2"/>
    <User id="person5" name="PQR" parentid="person1"/>
    <User id="person6" name="PQR" parentid="person7"/>
  </Users>
  <Users groupid="3">
    <User id="person7" name="ABC"  parentid="person11"/>
    <User id="person8" name="xyz"  parentid="person1"/>
    <User id="person3" name="LMN"  parentid="bac3"/>
    <User id="person4" name="PQR"  parentid="person2"/>
    <User id="person5" name="PQR" parentid="person1"/>
    <User id="person6" name="PQR" parentid="person7"/>
  </Users>
</root>

I need to transform this using xslt 1.0 to=>

<Users groupid="1">
  <User id="person1" name="ABC"  parentid="person7" haschildinGroup="yes"/>
      <User id="person2" name="xyz"  parentid="person1" haschildinGroup="yes"/>
          <User id="person4" name="PQR"  parentid="person2" haschildinGroup="no"/>
      <User id="person5" name="PQR" parentid="person1" haschildinGroup="no"/>
  <User id="person3" name="LMN"  parentid="bac3" haschildinGroup="no"/> 
  <User id="person6" name="PQR" parentid="person7" haschildinGroup="no"/>
</Users>
<Users groupid="3">
  <User id="person7" name="ABC"  parentid="person11" haschildinGroup="yes"/>
      <User id="person6" name="PQR" parentid="person7" haschildinGroup="no"/>
  <User id="person8" name="xyz"  parentid="person1" haschildinGroup="no"/>
  <User id="person3" name="LMN"  parentid="bac3" haschildinGroup="yes"/>
      <User id="person5" name="PQR" parentid="person3"  haschildinGroup="no"/>
  <User id="person4" name="PQR"  parentid="person2"  haschildinGroup="no"/>
</Users>

guide: 1) i need to group the values based on the people who share parentid and above output xml explains more

2) need to put xml like indentation for parent child relation(adding extra spaces in the first) for HTML view

I Tried Examples Like this but Key in this has scope on entire XML and not within current Node

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

      <xsl:key name="groups" match="User" use="@parentid" />
      <xsl:variable name="Space">&amp;nbsp;</xsl:variable>
      <xsl:variable name="addSpace" select="concat($Space,$Space)"/>

      <xsl:template match="/">
        <html>
          <table width="100%" cellspacing="0" cellpadding="0" border="0">
            <xsl:for-each select="root/Users/User[generate-id(.)=generate-id(key('groups',@parentid)[1])]">
              <xsl:call-template name="selectusers"></xsl:call-template>
            </xsl:for-each>
          </table>
        </html>
      </xsl:template>

      <xsl:template name="selectusers">
          <xsl:for-each select="key('groups', @parentid)">
            <tr>
               <xsl:value-of select="$addSpace" disable-output-escaping="yes"/><!--Works for only 1st Level need to add If-->
              <td>

                <xsl:value-of select="@id"/>
              </td>
              <td>
                <!--HasChild =:(-->
              </td>
            </tr>
          </xsl:for-each>
      </xsl:template>

    </xsl:stylesheet>
1

1 Answers

1
votes

Your XSLT is written to generate HTML instead of what you have described as your desired output, but I will assume that what you want is actually the HTML you were trying to produce. If so, this should do it:

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

  <xsl:key name="groups" match="User" use="concat(../@groupid, '+', @parentid)" />
  <xsl:variable name="Space">&#xA0;</xsl:variable>
  <xsl:variable name="addSpace" select="concat($Space,$Space)"/>

  <xsl:template match="/">
    <html>
      <table width="100%" cellspacing="0" cellpadding="0" border="0">
        <tr>
          <th>ID</th>
          <th>Has Children</th>
        </tr>
        <xsl:apply-templates 
              select="root/Users/User[not(@parentid = ../User/@id)]" />
      </table>
    </html>
  </xsl:template>

  <xsl:template match="User">
    <xsl:variable name="children"
                  select="key('groups', concat(../@groupid, '+', @id))" />

    <tr>
      <td>
        <xsl:apply-templates select="." mode="spacing" />
        <xsl:value-of select="@id"/>
      </td>
      <td>
        <xsl:value-of select="substring('No Yes', 1 + 3 * boolean($children), 3)"/>
      </td>
    </tr>
    <xsl:apply-templates select="$children" />
  </xsl:template>

  <xsl:template match="User" mode="spacing">
    <xsl:value-of select="$addSpace" />
    <xsl:apply-templates 
          select="../User[@id = current()/@parentid]" mode="spacing" />
  </xsl:template>
</xsl:stylesheet>

When this is run on your sample input, the result is:

<html>
  <table width="100%" cellspacing="0" cellpadding="0" border="0">
    <tr>
      <th>ID</th>
      <th>Has Children</th>
    </tr>
    <tr>
      <td>  person1</td>
      <td>Yes</td>
    </tr>
    <tr>
      <td>    person2</td>
      <td>Yes</td>
    </tr>
    <tr>
      <td>      person4</td>
      <td>No </td>
    </tr>
    <tr>
      <td>    person5</td>
      <td>No </td>
    </tr>
    <tr>
      <td>  person3</td>
      <td>No </td>
    </tr>
    <tr>
      <td>  person6</td>
      <td>No </td>
    </tr>
    <tr>
      <td>  person7</td>
      <td>Yes</td>
    </tr>
    <tr>
      <td>    person6</td>
      <td>No </td>
    </tr>
    <tr>
      <td>  person8</td>
      <td>No </td>
    </tr>
    <tr>
      <td>  person3</td>
      <td>No </td>
    </tr>
    <tr>
      <td>  person4</td>
      <td>No </td>
    </tr>
    <tr>
      <td>  person5</td>
      <td>No </td>
    </tr>
  </table>
</html>