Wrox Programmer Forums
Go Back   Wrox Programmer Forums > XML > XSLT
|
XSLT General questions and answers about XSLT. For issues strictly specific to the book XSLT 1.1 Programmers Reference, please post to that forum instead.
Welcome to the p2p.wrox.com Forums.

You are currently viewing the XSLT section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
 
Old January 31st, 2009, 12:56 PM
Friend of Wrox
 
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
Default

First of all, the xsl:key element does not belong into an xsl:template element. Instead it should be a top level element i.e. a child of the xsl:stylesheet element.

As for your key definition <xsl:key name="by-name" match="Request/*" use="SomeTypeB"/>, what is that supposed to achieve? It matches child elements of 'Request' elements and defines the key value with use="SomeTypeB". In your XML sample that you posted earlier the children of the 'Request' element do not have any child named 'SomeTypeB' so that key does not make any sense to me. You would need to have e.g.
Code:
<Request>
  <Foo>
    <SomeTypeB>whatever</SomeTypeB>
  </Foo>
</Request>
for that key to make any sense as then for the 'Foo' child element of the 'Request' element the string value of the 'SomeType' child element would be the key value.
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
 
Old January 31st, 2009, 01:05 PM
Authorized User
 
Join Date: Jan 2009
Posts: 17
Thanks: 2
Thanked 0 Times in 0 Posts
Default

Quote:
Originally Posted by Martin Honnen View Post
First of all, the xsl:key element does not belong into an xsl:template element. Instead it should be a top level element i.e. a child of the xsl:stylesheet element.

As for your key definition <xsl:key name="by-name" match="Request/*" use="SomeTypeB"/>, what is that supposed to achieve? It matches child elements of 'Request' elements and defines the key value with use="SomeTypeB". In your XML sample that you posted earlier the children of the 'Request' element do not have any child named 'SomeTypeB' so that key does not make any sense to me. You would need to have e.g.
Code:
<Request>
  <Foo>
    <SomeTypeB>whatever</SomeTypeB>
  </Foo>
</Request>
for that key to make any sense as then for the 'Foo' child element of the 'Request' element the string value of the 'SomeType' child element would be the key value.
I recognize now that it's wrong since especially you mentioened that the generate-id part is central to Meunchin grouping which I never had. I was also confused with the last part of the key statement .. i.e. the SomeTypeB .. in theory what I wanted to do was to create 2 keys for the <request> node:

1) 1 key containing all the SomeTypeB nodes
2) 1 key containing all other nodes in request.

I would then process each key with a for-each statment. I wanted to be able to just create a template to handle all of this. The actual key can be defined at the top I tried that too. But I always felt that my key definition was not correct.

How would I define a key which would create a set of nodes for SomeTypeB and another key (I was thinking a negation of the other key) for all non-SomeTypeB nodes and then process them using-for each statement?

Since the code I inherited calls templates explicitly it does not have any apply-templetes statements which I'm still confused about their order of execution. Calling templates explicitly is easier for me to understand as it's like Java methodology which I'm much more comfortable with.

Again, I appreciate your quick responses and great help. You're helping me to really understand the workings of XSLT

J
 
Old February 1st, 2009, 10:01 AM
Authorized User
 
Join Date: Jan 2009
Posts: 17
Thanks: 2
Thanked 0 Times in 0 Posts
Default

Hi Martin,

Sorry to bother you again. The post of what I'm trying to do exactly was approved by the admins .. it's post #17. If you can give me some pointers on what to do that would be really helpful as I'm still stuck on this issue

Thanks!

J
 
Old February 1st, 2009, 12:26 PM
Friend of Wrox
 
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
Default

Here is a sample stylesheet that should create the described output:
Code:
<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
  exclude-result-prefixes="soapenv"
  version="1.0">
  
  <xsl:output method="xml" indent="yes"/>
  <xsl:strip-space elements="*"/>
  
  <xsl:key name="by-name" match="request/*/*/*" use="name()"/>
  
  <xsl:template match="/soapenv:Envelope">
    <StepData>
      <Flow>
        <ProcessClassID>AGHExtractProc</ProcessClassID>
        <xsl:apply-templates select="soapenv:Body/callFlowRequest/LocaleID"/>
      </Flow>
      <Variables>
        <xsl:apply-templates select="soapenv:Body"/>
      </Variables>
    </StepData>
  </xsl:template>
  
  <xsl:template match="LocaleID">
    <xsl:element name="{name()}">
      <xsl:value-of select="."/>
    </xsl:element>
  </xsl:template>
  
  <xsl:template match="soapenv:Body">
    <Group name="Body">
      <xsl:apply-templates/>
    </Group>
  </xsl:template>
  
  <xsl:template match="callFlowRequest">
    <Group name="callFlowRequest">
      <xsl:apply-templates select="User"/>
      <xsl:apply-templates select="request"/>
    </Group>
  </xsl:template>
  
  <xsl:template match="User">
    <Variable name="User">
      <Value>
        <xsl:value-of select="."/>
      </Value>
    </Variable>
  </xsl:template>
  
  <xsl:template match="request">
    <Group name="Request">
      <xsl:apply-templates select="*/*/*[generate-id() = generate-id(key('by-name', name())[1])]"/>
    </Group>
  </xsl:template>
  
  <xsl:template match="request/*/*/*">
    <Group name="{name()}">
      <xsl:choose>
        <xsl:when test="key('by-name', name())[2]">
          <xsl:apply-templates select="key('by-name', name())/*" mode="item"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:apply-templates select="*"/>
        </xsl:otherwise>
      </xsl:choose>
    </Group>
  </xsl:template>
  
  <xsl:template match="request/*/*/*/*" mode="item">
    <Item>
      <Variable name="{name()}">
        <Value>
          <xsl:value-of select="."/>
        </Value>
      </Variable>
     </Item>
   </xsl:template>
   
   <xsl:template match="request/*/*/*/*">
     <Variable name="{name()}">
       <Value>
         <xsl:value-of select="."/>
       </Value>
     </Variable>
   </xsl:template>
  
</xsl:stylesheet>
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
 
Old February 2nd, 2009, 12:30 AM
Authorized User
 
Join Date: Jan 2009
Posts: 17
Thanks: 2
Thanked 0 Times in 0 Posts
Default

Quote:
Originally Posted by Martin Honnen View Post
Here is a sample stylesheet that should create the described output:
Code:
<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
  exclude-result-prefixes="soapenv"
  version="1.0">
 
  <xsl:output method="xml" indent="yes"/>
  <xsl:strip-space elements="*"/>
 
  <xsl:key name="by-name" match="request/*/*/*" use="name()"/>
 
  <xsl:template match="/soapenv:Envelope">
    <StepData>
      <Flow>
        <ProcessClassID>AGHExtractProc</ProcessClassID>
        <xsl:apply-templates select="soapenv:Body/callFlowRequest/LocaleID"/>
      </Flow>
      <Variables>
        <xsl:apply-templates select="soapenv:Body"/>
      </Variables>
    </StepData>
  </xsl:template>
 
  <xsl:template match="LocaleID">
    <xsl:element name="{name()}">
      <xsl:value-of select="."/>
    </xsl:element>
  </xsl:template>
 
  <xsl:template match="soapenv:Body">
    <Group name="Body">
      <xsl:apply-templates/>
    </Group>
  </xsl:template>
 
  <xsl:template match="callFlowRequest">
    <Group name="callFlowRequest">
      <xsl:apply-templates select="User"/>
      <xsl:apply-templates select="request"/>
    </Group>
  </xsl:template>
 
  <xsl:template match="User">
    <Variable name="User">
      <Value>
        <xsl:value-of select="."/>
      </Value>
    </Variable>
  </xsl:template>
 
  <xsl:template match="request">
    <Group name="Request">
      <xsl:apply-templates select="*/*/*[generate-id() = generate-id(key('by-name', name())[1])]"/>
    </Group>
  </xsl:template>
 
  <xsl:template match="request/*/*/*">
    <Group name="{name()}">
      <xsl:choose>
        <xsl:when test="key('by-name', name())[2]">
          <xsl:apply-templates select="key('by-name', name())/*" mode="item"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:apply-templates select="*"/>
        </xsl:otherwise>
      </xsl:choose>
    </Group>
  </xsl:template>
 
  <xsl:template match="request/*/*/*/*" mode="item">
    <Item>
      <Variable name="{name()}">
        <Value>
          <xsl:value-of select="."/>
        </Value>
      </Variable>
     </Item>
   </xsl:template>
 
   <xsl:template match="request/*/*/*/*">
     <Variable name="{name()}">
       <Value>
         <xsl:value-of select="."/>
       </Value>
     </Variable>
   </xsl:template>
 
</xsl:stylesheet>
Martin thank you very much on this! There is one final issue which my original input did not do a good job showing. For children of SomeTypeB the <Item> tags should be around them all not around each child:

Code:
<SomeTypeB>
   <Att1> A </Att1>
   <Att2> B </Att2>
</SomeTypeB>
<SomeTypeB>
   <Att1> A </Att1>
</SomeTypeB>
Therefore the output should be
Code:
<Group name = someTypeB>
    <Item>
          <Variable name = Att1>
                <Value> A </Value>
          <Variable name = Att2>
                <Value> B </Value>
     </Item>
     <Item>
             <Value> B </Value>
     </Item>
</Group>
I recogize your code groups together all children element of all <SomeTypeB> nodes and then processes them individually and applies the <Item> tags around each child. But like I note above I need all the children of each <SomeItemB> nodes to be under the same <Item> node but all overall <SomeItemB> nodes to be under the same Group.

I hope you're a Steleers fan and in good humour to help me out with this final contraption . Even though I fully understand what your code is doing and how it's doing it I'm still not able to change it to fit my needs here.

In any case, you've been a world of help!

Best regards,
J
 
Old February 2nd, 2009, 11:53 AM
Friend of Wrox
 
Join Date: Nov 2007
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 Posts
Default

Here is an adapted stylesheet that should do what you want:
Code:
<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
  exclude-result-prefixes="soapenv"
  version="1.0">
  
  <xsl:output method="xml" indent="yes"/>
  <xsl:strip-space elements="*"/>
  
  <xsl:key name="by-name" match="request/*/*/*" use="name()"/>
  
  <xsl:template match="/soapenv:Envelope">
    <StepData>
      <Flow>
        <ProcessClassID>AGHExtractProc</ProcessClassID>
        <xsl:apply-templates select="soapenv:Body/callFlowRequest/LocaleID"/>
      </Flow>
      <Variables>
        <xsl:apply-templates select="soapenv:Body"/>
      </Variables>
    </StepData>
  </xsl:template>
  
  <xsl:template match="LocaleID">
    <xsl:element name="{name()}">
      <xsl:value-of select="."/>
    </xsl:element>
  </xsl:template>
  
  <xsl:template match="soapenv:Body">
    <Group name="Body">
      <xsl:apply-templates/>
    </Group>
  </xsl:template>
  
  <xsl:template match="callFlowRequest">
    <Group name="callFlowRequest">
      <xsl:apply-templates select="User"/>
      <xsl:apply-templates select="request"/>
    </Group>
  </xsl:template>
  
  <xsl:template match="User">
    <Variable name="User">
      <Value>
        <xsl:value-of select="."/>
      </Value>
    </Variable>
  </xsl:template>
  
  <xsl:template match="request">
    <Group name="Request">
      <xsl:apply-templates select="*/*/*[generate-id() = generate-id(key('by-name', name())[1])]"/>
    </Group>
  </xsl:template>
  
  <xsl:template match="request/*/*/*">
    <Group name="{name()}">
      <xsl:choose>
        <xsl:when test="key('by-name', name())[2]">
          <xsl:apply-templates select="key('by-name', name())" mode="item"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:apply-templates select="*"/>
        </xsl:otherwise>
      </xsl:choose>
    </Group>
  </xsl:template>
  
  <xsl:template match="request/*/*/*" mode="item">
    <Item>
      <xsl:apply-templates select="*"/>
    </Item>
  </xsl:template>
   
   <xsl:template match="request/*/*/*/*">
     <Variable name="{name()}">
       <Value>
         <xsl:value-of select="."/>
       </Value>
     </Variable>
   </xsl:template>
  
</xsl:stylesheet>
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
 
Old February 3rd, 2009, 02:53 AM
Authorized User
 
Join Date: Jan 2009
Posts: 17
Thanks: 2
Thanked 0 Times in 0 Posts
Default Thank you!

The most gracious thank you Martin. You've been a world of help and my understanding of XSLT has greatly improved thanks to you - I tend to learn best by example.

J





Similar Threads
Thread Thread Starter Forum Replies Last Post
dynamic xslt -> xslt creation namespace problem jkmyoung XSLT 2 July 15th, 2006 12:42 AM
Help - I'm Completely Stuck [email protected] ASP.NET 1.x and 2.0 Application Design 1 May 16th, 2006 10:12 AM
Help!! I am completely stuck... andrewba Classic ASP Components 5 May 12th, 2005 04:50 AM
Data Shaping Problem .. im stuck! jeuriks SQL Server ASP 2 March 19th, 2004 11:09 AM
I'm stuck! budman Classic ASP Databases 2 November 3rd, 2003 12:52 AM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.