Dear James,
Wow! I am simply, just, totally impressed! I just copied and pasted your
solution a few hours ago and it worked at once. Then the strangest thing
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.
Well, that's not so strange, but I again copied and pasted your solution
to start all over, but didn't get the lovely result back, not even with
your sole solution, which worked before. I know, something must have
changed, but I couldn't find it. Even undoing to very first beginning
didn't give me back that euforic moment.
Not to worry, after several hours of really losing the feeling that I
understood something of xslt, I tweaked a little the bold way, just
inserting stuff where I wanted it in the output stream, leaving the
overall framework as it was delivered by you.
Somehow, I figured that this "catch all" was not catching "all", and
because every element has an "@id" attribute, the xsl:choose did not
quite work. But then again, why *did* it work in the first place? I'm at
a loss here and must admit that I understand far less of functional
programming than I thought.
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.
Cheers!
Abel
STYLESHEET:
<?xml version="1.0" encoding="UTF-8"?>
<?altova_samplexml D:\Workspaces\Eclipse
Nuntia\nuntia-spline-tablewiz\resources\examples\xml\getTableNamesResponse.xml?>
<xsl:stylesheet version="1.0"
exclude-result-prefixes="twz xsl"
xmlns:twz="http://www.nuntia.com/tablewiz1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!--
NOTE: xpath-default-namespace cannot be used in XSLT 1.0. And browser
don't understand XSLT 2.0 yet. Be aware that only XSLT 1.0 features can
be used
-->
<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="/">
<tree id="0">
<!-- process the first tableName with a category-name
matching 'Root' -->
<xsl:apply-templates
select="//twz:tableName[(_at_)category-name='Root'][1]" />
</tree>
</xsl:template>
<!--
Process each 1st tableName by emitting an item and
then processing its descendents and then its children.
-->
<xsl:template
match="twz:tableName[generate-id(.)=generate-id(key('table-by-category',
@category-name)[1])]">
<item text="{(_at_)category-name}" id="{(_at_)category-name}">
<!-- process each 1st tableName which has a parent-category-name
matching our category-name -->
<xsl:apply-templates
select="//twz:tableName
[(_at_)category-parent-name=current()/@category-name]
[generate-id(.)=generate-id(key('table-by-category',
@category-name)[1])]" />
<!-- process all other tableName entries with the same
category-name -->
<xsl:apply-templates
select="key('table-by-category',@category-name)[position() != 1]" />
<!-- make sure to create an item of this category as well -->
<item text="{string(.)}" id="{(_at_)id}" />
</item>
</xsl:template>
<!--
Catch-all rule to emit an item for each tableName, not processing
any children or siblings.
-->
<xsl:template match="twz:tableName">
<item text="{string(.)}" id="{(_at_)id}" />
</xsl:template>
</xsl:stylesheet>
INPUT
<response xmlns="http://www.nuntia.com/tablewiz1.0"
response="getTableNames" application="tablewiz" table-mnemonic="generic">
<responseMessage response-status="success">Table names retrieved
successfully!</responseMessage>
<userData timestamp="648289332528" request="getTableNames"
client-version="1.0 beta"/>
<tableName id="5" category-name="Root">testcsv3</tableName>
<tableName id="7" category-name="Root">[New table 2]</tableName>
<tableName id="8" category-name="Root">ee</tableName>
<tableName id="9" category-name="Personnel"
category-parent-name="General">Child of Personnel</tableName>
<tableName id="10" category-name="Personnel"
category-parent-name="General">Other personnel member</tableName>
<tableName id="11" category-name="Personnel"
category-parent-name="General">Final personnel member</tableName>
<tableName id="12" category-name="Printers"
category-parent-name="Root">List of printers locally</tableName>
<tableName id="13" category-name="Printers"
category-parent-name="Root">External Oce printers</tableName>
<tableName id="14" category-name="Root">Very rooty table</tableName>
<tableName id="15" category-name="General"
category-parent-name="Root">General usage table</tableName>
<tableName id="16" category-name="General"
category-parent-name="Root">General cooking table</tableName>
<tableName id="17" category-name="General"
category-parent-name="Root">General General</tableName>
<tableName id="18" category-name="General"
category-parent-name="Root">Genes of mambutam</tableName>
<tableName id="19" category-name="General"
category-parent-name="Root">Generosity clears</tableName>
<tableName id="20" category-name="Signatures"
category-parent-name="Personnel">List of signatures</tableName>
</response>
OUTPUT:
<tree id="0">
<item text="Root" id="Root">
<item text="Printers" id="Printers">
<item text="External Oce printers" id="13"/>
<item text="List of printers locally" id="12"/>
</item>
<item text="General" id="General">
<item text="Personnel" id="Personnel">
<item text="Signatures" id="Signatures">
<item text="List of signatures" id="20"/>
</item>
<item text="Other personnel member" id="10"/>
<item text="Final personnel member" id="11"/>
<item text="Child of Personnel" id="9"/>
</item>
<item text="General cooking table" id="16"/>
<item text="General General" id="17"/>
<item text="Genes of mambutam" id="18"/>
<item text="Generosity clears" id="19"/>
<item text="General usage table" id="15"/>
</item>
<item text="[New table 2]" id="7"/>
<item text="ee" id="8"/>
<item text="Very rooty table" id="14"/>
<item text="testcsv3" id="5"/>
</item>
</tree>
James A. Robinson wrote:
I'm afraid I'm not following what you want done with the namespaces,
but in general I think that if you are stuck doing this in XSLT 1.0
you can achieve your goal of emitting a tree from a flat list by using
the Muenchian grouping technique:
http://www.jenitennison.com/xslt/grouping/muenchian.html
I'm dashing this off before I head to work, so apologies if it isn't
as complete as you spec out. I *think* it does what you want in terms
of the tree structure. Apologies if I've misunderstood what you are
after!
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:abel="http://something.com">
<xsl:output indent="yes" />
<!-- table-by-category lets us look up all tableName elements matching a category
-->
<xsl:key name="table-by-category" match="abel:tableName" use="@category-name"
/>
<!--
At the root of our output tree emit the tableName for 'Root'
-->
<xsl:template match="/">
<xsl:element name="abel:tree">
<xsl:attribute name="id">0</xsl:attribute>
<!-- process the first tableName with a category-name matching 'Root' -->
<xsl:apply-templates select="//abel:tableName[(_at_)category-name='Root'][1]"
/>
</xsl:element>
</xsl:template>
<!--
Process each 1st tableName by emitting an item and
then processing its descendents and then its children.
-->
<xsl:template
match="abel:tableName[generate-id(.)=generate-id(key('table-by-category',
@category-name)[1])]">
<xsl:element name="abel:item">
<xsl:attribute name="text">
<xsl:value-of select="string(.)" />
</xsl:attribute>
<xsl:attribute name="id">
<xsl:choose>
<xsl:when test="@id">
<xsl:value-of select="@id" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="@category-name" />
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<!-- process each 1st tableName which has a parent-category-name matching our
category-name -->
<xsl:apply-templates select="//abel:tableName
[(_at_)category-parent-name=current()/@category-name]
[generate-id(.)=generate-id(key('table-by-category',
@category-name)[1])]" />
<!-- process all other tableName entries with the same category-name -->
<xsl:apply-templates select="key('table-by-category',@category-name)[position() !=
1]" />
</xsl:element>
</xsl:template>
<!--
Catch-all rule to emit an item for each tableName, not processing
any children or siblings.
-->
<xsl:template match="abel:tableName">
<xsl:element name="abel:item">
<xsl:attribute name="text">
<xsl:value-of select="string(.)" />
</xsl:attribute>
<xsl:attribute name="id">
<xsl:choose>
<xsl:when test="@id">
<xsl:value-of select="@id" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="@category-name" />
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
</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>
--~--
--~------------------------------------------------------------------
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>
--~--