Re: [xsl] Keys with different parents, but same name

Subject: Re: [xsl] Keys with different parents, but same name
From: Wendell Piez <wapiez@xxxxxxxxxxxxxxxx>
Date: Fri, 24 Oct 2003 18:41:20 -0400
Hi Ganesh,

At 04:24 PM 10/24/2003, you wrote:
I'm a bit stuck in usage of XSLT lookup tables using
xsl:key.
I'm sure someone on the list can help me or direct me
in the right direction.

I've looked at your code, though I haven't banged on it hard enough to know everything it's doing, and see a few problems with it.


Rather than try to sort them out, however, I think just pointing you in the right direction, as you requested, should suffice.

Rather than use two different keys, one that retrieves fields by @id, the other that retrieves fieldGroups by @id, I'd use a single key. Construct it like this:

<xsl:key name="label-by-field" match="label" use="concat(ancestor::fieldgroup/@id, '-', parent::field/@id)"/>

Notice this is a compound key. It retrieves a <label> element (I'm going straight for the label), using the concatenation of its grandparent or parent fieldgroup's @id (if it doesn't have one, this will be '') and its parent field's @id (again this will be '' if there is no parent field).

So you will have key values such as
   '-customerId' (the label retrieved has value "Customer Id : ")
   'homeAddress-' (the label is "House Address")
   'homeAddress-street' (the label retrieved is "Street").

Then, when processing a fieldGroup, you can retrieve its label simply by doing:

<xsl:variable name="keyvalue" select="concat(@id,'-')"/>
<xsl:for-each select="$fieldHeaders">
  <xsl:value-of select="key('label-by-field', $keyvalue)"/>
</xsl:for-each>

...and when processing a field, you can get its label likewise:

<xsl:variable name="keyvalue"
   select="concat(ancestor::fieldGroup/@id,'-',@id)"/>
<xsl:for-each select="$fieldHeaders">
  <xsl:value-of select="key('label-by-field', $keyvalue)"/>
</xsl:for-each>

Notice both times you have first to bind your key value to a variable, then change your context node to the fieldHeaders document so you can retrieve your labels from there.

Note: untested. But I hope the concept is clear. Also I'm assuming that you have only one layer of fieldGroup wrapping your fields.

Cheers,
Wendell

I have created a stylesheet which would render the xml
document by picking up the
labels for the fields from a separate document.  The
'field' is used as key.
These 'field' elements could be contained within group
so they are repeatable e.g. field@id = city, but label
for them would be different
depending upon the group they are in like in this case
for home address it is called City and for company
address its Location.

The problem i am facing is I am always getting the
first 'field' element.  The way i have done could be
wrong.

I tried looking into all the archives, but could not
find anything related to this.

How do I get the label related to field element wrt
its parent.  Any Help would be greatly appreciated.

Thanks,
Ganesh.

Here is my styleSheet:

<?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" method="html"/>

   <xsl:key name="field-lookup" match="field"
use="@id"/>

   <xsl:key name="fieldGroup-lookup"
match="fieldGroup" use="@id"/>

   <xsl:variable name="fieldHeaders"
select="document('Headers.xml')/fieldHeaders"/>


<xsl:template match="/"> <html> <style type="text/css"> body {color:black; background-color: white} </style> <body> <table border="1"> <xsl:apply-templates/> </table> </body> </html> </xsl:template>

   <xsl:template match="customer">
      <br />
       <table border="1"> <xsl:apply-templates />
</table>
   </xsl:template>
   <xsl:template match="fieldGroup">
      <TR>
         <TD colspan="2" bgcolor="CCAA00"
style="font-family:verdana;font-size:80%;color:white">
            <xsl:apply-templates
select="$fieldHeaders">
               <xsl:with-param name="curr-label"
select="."/>
            </xsl:apply-templates>
         </TD>
      </TR>
      <xsl:apply-templates/>
   </xsl:template>

   <xsl:template match="fieldList">
      <xsl:apply-templates select="field"/>
   </xsl:template>

   <xsl:template match="field">
      <TR>
         <TD bgcolor="00AACC"
style="font-family:verdana;font-size:80%;color:white">
            <xsl:apply-templates
select="$fieldHeaders">
               <xsl:with-param name="curr-label"
select="."/>
            </xsl:apply-templates>
         </TD>
         <TD>
            <xsl:value-of select="text()"/>
         </TD>
      </TR>
   </xsl:template>

   <xsl:template match="fieldHeaders">
      <xsl:param name="curr-label"/>
      <xsl:variable name="switch"
select="name($curr-label/.)"/>
      <xsl:variable name="parent"
select="name($curr-label/..)"/>
      <xsl:value-of select="key(concat($switch,
'-lookup'), $curr-label/@id)/label"/>
   </xsl:template>

</xsl:stylesheet>

Here is XML document:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="format.xsl"?>
<customerList>
   <customer>
      <field id="customerId">cust1</field>
      <field id="customerName">Customer 1</field>
      <fieldGroup id="homeAddress">
         <fieldList>
            <field id="street">98th Street</field>
            <field id="city">Chicago</field>
         </fieldList>
      </fieldGroup>
      <fieldGroup id="companyAddress">
         <fieldList>
            <field id="street">128th Street</field>
            <field id="city">Chicago</field>
         </fieldList>
      </fieldGroup>
   </customer>
   <customer>
      <field id="customerId">cust2</field>
      <field id="customerName">Customer 2</field>
      <fieldGroup id="homeAddress">
         <fieldList>
            <field id="street">13th Street</field>
            <field id="city">TeaNeck</field>
         </fieldList>
      </fieldGroup>
      <fieldGroup id="companyAddress">
         <fieldList>
            <field id="street">12th Street</field>
            <field id="city">New York</field>
         </fieldList>
      </fieldGroup>
   </customer>
</customerList>

Here is Headers.xml :

<?xml version="1.0" standalone="yes"?>
<fieldHeaders>
   <field id="customerId">
      <label>Customer Id : </label>
   </field>
   <field id="customerName">
      <label>Customer Name : </label>
   </field>
   <fieldGroup id="homeAddress">
      <label>House Address</label>
      <field id="street">
         <label>Street</label>
      </field>
      <field id="city">
         <label>City : </label>
      </field>
   </fieldGroup>
   <fieldGroup id="companyAddress">
      <label>Company Address</label>
      <field id="street">
         <label>Street : </label>
      </field>
      <field id="city">
         <label>Location : </label>
      </field>
   </fieldGroup>
</fieldHeaders>


======================================================================
Wendell Piez                            mailto:wapiez@xxxxxxxxxxxxxxxx
Mulberry Technologies, Inc.                http://www.mulberrytech.com
17 West Jefferson Street                    Direct Phone: 301/315-9635
Suite 207                                          Phone: 301/315-9631
Rockville, MD  20850                                 Fax: 301/315-8285
----------------------------------------------------------------------
  Mulberry Technologies: A Consultancy Specializing in SGML and XML
======================================================================


XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list



Current Thread