Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Repeating template for each sibling 2

Status
Not open for further replies.

MikeAJ

Programmer
May 22, 2002
108
0
0
US
Hello, I'm trying to use XSL to the fullest by using templates instead of repeating my code. I have "PART" nodes that can be in the root document itself, or can be embedded in one or many levels deep in an "OPTION_CLASS" tag. Anytime I find at least one child PART node, I need to create a table and a form, and then loop through all of the parts on the same level, to create the table lines. I think I'm pretty close, I just need to properly select the PART siblings.

XML:
Code:
<PACKAGE id = "1">
   <OPTION_CLASS id = "2">
      <OPTION_CLASS id = "3">
         <PART id = "4"/>
         <PART id = "4"/>
         <PART id = "4"/>
         <OPTION_CLASS id = "5">
            <PART id = "6"/>
            <PART id = "6"/>
         </OPTION_CLASS>
      </OPTION_CLASS>
      <PART id = "7"/>
      <PART id = "7"/>
      <PART id = "7"/>
   </OPTION_CLASS>
   <OPTION_CLASS id = "8">
      <PART id = "9"/>
      <PART id = "9"/>
   </OPTION_CLASS>
   <PART id = "10"/>
   <PART id = "11"/>
</PACKAGE>

Main Template:
Code:
<xsl:template match = "/*">
   <!--### I don't know if [position()=1] is correct, but it would repeat the form otherwise ###-->
   <xsl:apply-templates select="PART[position()=1]" mode="form"/> 
   <xsl:apply-templates select="/BUNDLE/OPTION_CLASS"/>
</xsl:template>

Part Form Template:
Code:
<xsl:template match="PART" mode="form">
   <p/>
   <form action = "part" method = "get">
      <input type = "hidden" name = "p_action" value = "UPDATE_LINE"/>
      <table cellpadding = "3" bgcolor = "#F5F5FF">
         <tr>
            <th>Part Number</th>
            <th>Sequence</th>
            <th>Optional</th>
            <th>Pre-Selected</th>
         </tr>
         <!--###HERE IS WHERE I NEED TO SELECT ALL PART SIBLINGS###-->
         <xsl:apply-templates select="./PART" mode="line"/> 
         <tr>
            <td colspan = "4"><input type = "submit" value = "Update Parts"/></td>
         </tr>
      </table>
   </form>
</xsl:template>

Part Line Template:
Code:
<xsl:template match="PART" mode="line">
   <input type = "hidden" name = "p_header_id">
      <xsl:attribute name = "value">
         <xsl:value-of select = "@header_id"/>
      </xsl:attribute>
   </input>
   <input type = "hidden" name = "p_line_id">
      <xsl:attribute name = "value">
         <xsl:value-of select = "@line_id"/>
      </xsl:attribute>
   </input>
   <tr>
      <td><xsl:value-of select = "@part_number"/></td>
      <td>
         <input type = "text" name = "p_sequence" size = "3" autocomplete = "OFF">
            <xsl:attribute name = "value">
               <xsl:value-of select = "@sequence"/>
            </xsl:attribute>
         </input>
      </td>
      <td>
         <select name = "p_optional">
            <xsl:if test = "@optional = 'Y'">
               <option value="Y" selected="true">Yes</option>
               <option value="N">No</option>
            </xsl:if>
            <xsl:if test="@optional != 'Y'">
               <option value="Y">Yes</option>
               <option value="N" selected="true">No</option>
            </xsl:if>
         </select>
      </td>
      <td>
         <select name = "p_default_flag">
            <xsl:if test = "@default_flag = 'Y'">
               <option value="Y" selected="true">Yes</option>
               <option value="N">No</option>
            </xsl:if>
            <xsl:if test="@default_flag != 'Y'">
               <option value="Y">Yes</option>
               <option value="N" selected="true">No</option>
            </xsl:if>
         </select>
      </td>
   </tr>
</xsl:template>

So how can I print the table and form if I see at least 1 PART node, and then loop through all the parts on that level?

Thanks,
Mike
 
How about this?
Code:
[small]<?xml version='1.0'?>
<xsl:stylesheet version="1.0" xmlns:xsl="[URL unfurl="true"]http://www.w3.org/1999/XSL/Transform">[/URL]
<xsl:output indent="yes"/>

<xsl:template match="/">
	<html>
	<body>
	<xsl:apply-templates/>
	</body>
	</html>
</xsl:template>

<xsl:template match = "*">
   <xsl:if test="count(PART) &gt; 0">
   <p/>
   <form action = "part" method = "get">
      <input type = "hidden" name = "p_action" value = "UPDATE_LINE"/>
      <table cellpadding = "3" bgcolor = "#F5F5FF">
         <tr>
            <th>Part Number</th>
            <th>Sequence</th>
            <th>Optional</th>
            <th>Pre-Selected</th>
         </tr>
         <xsl:apply-templates select="PART"/>
         <tr>
            <td colspan = "4"><input type = "submit" value = "Update Parts"/></td>
         </tr>
      </table>
   </form>
   </xsl:if>
   <xsl:apply-templates select="*[local-name() != 'PART']"/>
</xsl:template>

<xsl:template match="PART">
   <input type = "hidden" name = "p_header_id">
      <xsl:attribute name = "value">
         <xsl:value-of select = "@header_id"/>
      </xsl:attribute>
   </input>
   <input type = "hidden" name = "p_line_id">
      <xsl:attribute name = "value">
         <xsl:value-of select = "@line_id"/>
      </xsl:attribute>
   </input>
   <tr>
      <td><xsl:value-of select = "@part_number"/></td>
      <td>
         <input type = "text" name = "p_sequence" size = "3" autocomplete = "OFF">
            <xsl:attribute name = "value">
               <xsl:value-of select = "@sequence"/>
            </xsl:attribute>
         </input>
      </td>
      <td>
         <select name = "p_optional">
            <xsl:if test = "@optional = 'Y'">
               <option value="Y" selected="true">Yes</option>
               <option value="N">No</option>
            </xsl:if>
            <xsl:if test="@optional != 'Y'">
               <option value="Y">Yes</option>
               <option value="N" selected="true">No</option>
            </xsl:if>
         </select>
      </td>
      <td>
         <select name = "p_default_flag">
            <xsl:if test = "@default_flag = 'Y'">
               <option value="Y" selected="true">Yes</option>
               <option value="N">No</option>
            </xsl:if>
            <xsl:if test="@default_flag != 'Y'">
               <option value="Y">Yes</option>
               <option value="N" selected="true">No</option>
            </xsl:if>
         </select>
      </td>
   </tr>
</xsl:template>

</xsl:stylesheet>[/small]

Tom Morrison
 
[1]
><!--### I don't know if [position()=1] is correct, but it would repeat the form otherwise ###-->
><xsl:apply-templates select="PART[position()=1]" mode="form"/>
It should be fine.
[2]
><!--###HERE IS WHERE I NEED TO SELECT ALL PART SIBLINGS###-->
><xsl:apply-templates select="./PART" mode="line"/>
[tt]<xsl:apply-templates select="[blue]following-sibling::[/blue]PART" mode="line"/>[/tt]
 
Thanks for the response guys! I appreciate it! tsuji, your example plugged right in and almost worked perfectly. It's successfully looping for each sibling, but it doesn't print out a line for the first one. I copied the code in the part line template to the part form. So it's working correctly, but I don't think I need to duplicate that code. How can I include the first node in your example?

<xsl:apply-templates select="following-sibling::pART" mode="line"/>

Thanks again,
Mike
 
Mike,

but it doesn't print out a line for the first one

It is for this reason that I restructured your code.

The select attribute selects a node set. You can select multiple things with an or operator. You probably could also get away with [tt]select="../PART"[/tt] as well. It just seems like an odd way to structure the templates.

Tom Morrison
 
>[self]<xsl:apply-templates select="following-sibling::pART" mode="line"/>

To include the PART[position()=1] itself in the template of mode form matching it, you can change it to this (using the same spirit of exhibiting explicitly axes.

[tt] <xsl:apply-templates select="self::pART | following-sibling::pART" mode="line"/>[/tt]

If you have not designed template in all sort of odd form, it is indeed very illustrative of how axes can blend together. In the form of not exhibiting axes, sure you can simply use this.

[tt] <xsl:apply-templates select="../PART" mode="line"/>[/tt]

And it is proper too because of xml being built on a tree structure.
 
For the last observation, I meant, quote, And it is proper too because of xml being built on a tree structure, unquote, [blue]and it is initiated from the PART of position()=1[/blue].
 
Thank you both for your comments and feedback. I'm still in the discovery phase with XSL. So I appreciate your help and insight.

Thanks,
Mike
 
k5tm being stupid said:
You can select multiple things with an or operator
Umm. Typed that too late at night. I meant union operator (coded using the vertical bar character as demonstrated by tsuji). [blush]

Tom Morrison
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top