[XSL-LIST Mailing List Archive Home] [By Thread] [By Date]

[xsl] Restrict Key to specific parent


Subject: [xsl] Restrict Key to specific parent
From: "Ty Molchany" <ty.molchany@xxxxxxxxx>
Date: Wed, 29 Nov 2006 14:44:58 -0500

Hello,
This is as simple of an example, hitting the main scenarios, I could
come up with.

I will try and be as clear and unambiguous as possible. I did research
throughout the xsl-list archive and found posts that were close, but
did not really hit my issue here.
I will start with an input xml, show the output expected and then show
you what I tried and it's short comings. So here goes.

Input XML:
<Root>
<Info>
<Prod name="Red"/>
<Prod name="Blue"/>
<Prod name="Green"/>
</Info>
<Title>Test Document</Title>
<Section>
<Paragraph>
 This is regular text for these product: <Name/>
 <Profile>
  <ProfileInfo Name="Blue"/>
   <!-- The issue here is that we cannot be sure how deep the
<Name/> element is from the <Profile> and <ProfileInfo> element -->
  This is text associated with Prod Profile: <bold><Name/></bold>
 </Profile>
 This is text after the profile that is for all Prods: <Name/>
 <Profile>
  <ProfileInfo Name="Red"/>
  <ProfileInfo Name="Green"/>
  This is text associated with Product Profile for <Name/>
 </Profile>
</Paragraph>
<Paragraph>
 This is some more text.
 <Profile>
  <ProfileInfo Name="Blue"/>
  More text associated with <Name/>
 </Profile>
</Paragraph>
</Section>
<Section>
<ProfileInfo Name="Green"/>
<Paragraph>
 This is text that goes along with this section for <Name/>
</Paragraph>
</Section>
</Root>


Expected Output:


<Title>Test Document</Title>

<Section>
<Paragraph>
This is regular text for these products: Red, Blue, Green

<Profile>
 This is text associated with Product Profile for <bold>Blue</bold>
</Profile>

This is text after the profile that is for all products: Red, Blue, Green
<Profile>
 This is text associated with Product Profile for Red, Green
</Profile>

</Paragraph>

<Paragraph>
This is some more text.

<Profile>
  More text associated with Blue
</Profile>

</Paragraph>
</Section>

<Section>
<Profile>
This is text that goes along with this section for Green
</Profile>
</Section>

Ok, so the rules that we want to abide by are as follows: (The only
template that I am having trouble with is the <Name> tag, I can
correctly I identify and resolve all other tags)

1) If there is a <Name/> Element within a <Profile> element, then
take all the ProfileInfo elements that are children of the <Profile>
element and display their @Name attribute uniquely and separated by
commas.
2) If there is a <Name/> Element within a <Section> element, and the
<Section> has a <ProfileInfo> in it (the ProfileInfo will have to come
directly after the <Section> element defined by the schema.) then
output only the @Name of the <ProfileInfo>(s) associated with that
particular <Section>
3) If there is a <Name/> Element that does not reside in a <Profile>
element (which has a profile element) or within a <Section> element
that is profiled (has a <ProfileInfo> tag) then we want to output all
Prod/@name separated by commas and non repeating.


The main question is: How to scope the <xsl:key>'s when I'm in the <xsl:for-each> such that only the profiles of that specific section are looked at, not the entire document which is happening here.

Here's what I have: (My namespace is _ for convenience)

<xsl:key name="distinct-name" match="_:Prod" use="@name" />
<xsl:key name="distinct-name-profiled" match="_:ProfileInfo" use="@Name" />

<xsl:template match="_:Name">
<xsl:choose>
 <xsl:when test="ancestor::_:ProductProfile">

   <xsl:for-each
select="preceding::_:ProfileInfo[generate-id(.)=generate-id(key('distinct-name-profiled',@Name)[1])]">
    <span>
     <xsl:value-of select="@Name"/>
     <xsl:if test="position() != last()">, </xsl:if>
    </span>
    </xsl:for-each>

 </xsl:when>
 <xsl:when test="not(ancestor::_:ProductProfile) and preceding::_:Section">

   <xsl:for-each
select="preceding::_:ProfileInfo[generate-id()=generate-id(key('distinct-name-profiled',@Name)[1])]">
    <span>
     <xsl:value-of select="@Name"/>
     <xsl:if test="position() != last()">, </xsl:if>
    </span>
    </xsl:for-each>

 </xsl:when>
 <xsl:otherwise>

  <xsl:for-each
select="//_:Prod[generate-id()=generate-id(key('distinct-name',@name))]">
   <span>
    <xsl:value-of select="@name"/>
    <xsl:if test="position() != last()">, </xsl:if>
   </span>
   </xsl:for-each>

 </xsl:otherwise>
</xsl:choose>

</xsl:template>

Please let me know if there is anything else that you man need.

Thanks again for all your time,
-Ty


Current Thread
Keywords
xml