xsl-list
[Top] [All Lists]

Re: [xsl] XSLT 1: From flat XML to tree hierarchy XML. Can't seem to find the right way to do it.

2006-05-25 15:32:08

happened: tweaking the solution a bit to get rid of the namespace 
prefixes (that's what the target system can't quite well deal with, and 
MS 3.0/4.0 processor does not work quite well with 
exclude-result-prefixes in all circumstances, or I just do something 
wrong there: the prefixes are not removed) and soon the output changed.

Perhaps the input changed? If, for example, the namespace changed, my
example would have stopped working unless it was updated to reflect
the new namespace.


Below is my solution, input, output and xslt all from live system. I 
post it here, because perhaps you can tell me / help me with 
understanding why the simpler and more straightforward solution of you 
is not working anymore, and where I went wrong along the way (btw, for 
brevity, I removed your xsl:element with just the elements themselves. 
Not sure if that's a best practice, but anyway).

Thanks a lot for your time and effort, I think I couldn't ever come up 
with this myself. I should learn about the key/generate-id thing hoping 
to somehow understand. it.

I see now that I misunderstood what your desired output was.  I hadn't
picked up on the fact that you were wanting a container element for
each 1st tableName/@category-name, and then an 'item' within the
container which corresponded to that 1st tableName/@category-name.

That does add to the complexity, the match I specified to catch the
1st tableName/@category-name basically prevents you from doing a
simple apply-templates to include it in your container.

I tweaked my example to reflect my current understanding of what you
need.  It is similar to what you are doing, but it shows how you can
use mode selection to keep the code which emits an 'item' element in
one place.

I think your use of literal result elements is fine, I've thought of
it as just a matter of style.  I'd be curious if people on this list
have opinions on whether or not they've come up with rules for when to
use literal result elements and when to use xsl:element.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="1.0"
                xmlns:twz="http://www.nuntia.com/tablewiz1.0";>

  <xsl:output indent="yes" />

  <!-- table-by-category lets us look up all tableName elements matching a 
category -->
  <xsl:key name="table-by-category" match="twz:tableName" use="@category-name" 
/>

  <!-- 
    At the root of our output tree emit the tableName for 'Root' -->
  <xsl:template match="/">
    <xsl:element name="tree">
      <xsl:attribute name="id">0</xsl:attribute>
      <!-- process the first tableName with a category-name matching 'Root' -->
      <xsl:apply-templates 
select="//twz:tableName[(_at_)category-name='Root'][1]" />
    </xsl:element>
  </xsl:template>

  <!-- 
    Emit a general item node for every 1st instance of a tableName
    with a specific category-name. Then process children, siblings,
    and self. -->
  <xsl:template 
match="twz:tableName[generate-id(.)=generate-id(key('table-by-category', 
@category-name)[1])]">
    <xsl:element name="item">
      <xsl:attribute name="text">
        <xsl:value-of select="@category-name" />
      </xsl:attribute>
      <xsl:attribute name="id">
        <xsl:value-of select="@category-name" />
      </xsl:attribute>

      <!-- process each 1st tableName which has a parent-category-name matching 
ours  -->
      <xsl:apply-templates select="//twz:tableName
                  [(_at_)category-parent-name=current()/@category-name]
                  [generate-id(.)=generate-id(key('table-by-category', 
@category-name)[1])]" />

      <!-- emit item for each tableName with this category-name, in document 
order -->
      <xsl:apply-templates mode="item" 
select="key('table-by-category',@category-name)" />
      <!--
        You could replace the line above with the following two lines of code 
if you needed
        the current tableName emitted as the last item in the sequence. -->
      <!--
      <xsl:apply-templates mode="standalone" 
select="key('table-by-category',@category-name)[position() != 1]" />
      <xsl:apply-templates mode="standalone" select="." />
      -->

    </xsl:element>
  </xsl:template>

  <!--
    Catch-all rule to emit an item for each tableName,
    not processing any children or siblings. -->
  <xsl:template mode="item" match="twz:tableName">
    <xsl:element name="item">
      <xsl:attribute name="text">
        <xsl:value-of select="string(.)" />
      </xsl:attribute>
      <xsl:copy-of select="@id" />
    </xsl:element>
  </xsl:template>

</xsl:stylesheet>

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
James A. Robinson                       
jim(_dot_)robinson(_at_)stanford(_dot_)edu
Stanford University HighWire Press      http://highwire.stanford.edu/
+1 650 7237294 (Work)                   +1 650 7259335 (Fax)

--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--