xsl-list
[Top] [All Lists]

RE: Specify/determine element's "logical" parent

2004-09-23 16:16:10
... surprised and frustrated at how 
difficult and complicated it seems for a beginner

I am always frustrated at how long it takes to get to grips with a new
technology, but I am never surprised by it. It's what you should expect; and
the more powerful the technology, the steeper the learning curve is likely
to be.

I think I need to take a few weeks off and 
research XSL but I have deliverables. 

The problem is that you're trying to run before you have learned to walk.
There are no short-cuts; learning new skills takes time.

For instance, I do not understand the difference between the 
two templates
listed below, which seem equivalent to me.  The first one 
fails ("Reference to
variable or parameter 'parent' must evaluate to a node list") 
while the second
works.  Nor do I understand why when both templates are in a single
stylesheet, only one (the latter?) seems to get applied.  Any help or
suggestions would be appreciated - hopefully I am doing 
something really
stupid and obvious (at least I got rid of xsl:for-each!).

The way you use xsl:variable in the first example, you are creating a new
XML document whose content is a copy of some of the content in your source
document. That new document does not have an id attribute (in fact,
documents never have attributes, only elements have attributes).

What you are trying to do is to set the variable to be a reference to a node
in the source document. In XSLT 2.0 you can do this using the expression:

<xsl:variable name="parent"
   select="if (@parentid) 
           then key( 'ids', @parentid )
           else key( 'ids', ../@id )"/>

It's trickier in XSLT 1.0 because XPath 1.0 doesn't have conditional
expressions: but if you want a variable to be a reference to an existing
node, rather than a newly constructed node containing a copy of the data,
you need to use the "select" attribute.

In this case there's a workaround. The @parentid attribute, if it exists,
will always be after the ../@id attribute in document order. So the
expression 

(../@id | @parentid) [last()]

will select the @parentid attribute if it exists, and the ../@id attribute
otherwise. So you can write:

<xsl:variable name="parent" select="key('ids', (../@id | @parentid)
[last()])"/>

I'm afraid that XSLT coding, especially in 1.0, is full of such tricks, and
there's no way to learn them except by experience.

Michael Kay
http://www.saxonica.com/
 

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
<xsl:key name="ids" match="item" use="@id"/>

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

<xsl:template match="item">
  <xsl:if test="../@id">
    <xsl:variable name="parent">
      <xsl:choose>
        <xsl:when test="@parentid">
<!-- following line differs -->
          <xsl:value-of select="key( 'ids', @parentid )" />
        </xsl:when>
        <xsl:otherwise>
<!-- following line differs -->
          <xsl:value-of select="key( 'ids', ../@id )" />
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
<!-- following line differs -->
    <xsl:value-of select="@id" /> is [<xsl:value-of 
select="$parent/@id" />]<br />
  </xsl:if>
</xsl:template>

<xsl:template match="item">
  <xsl:if test="../@id">
    <xsl:variable name="parent">
      <xsl:choose>
        <xsl:when test="@parentid">
          <xsl:value-of select="key( 'ids', @parentid )/@id" />
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="key( 'ids', ../@id )/@id" />
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:value-of select="@id" /> is [<xsl:value-of 
select="$parent" />]<br />
  </xsl:if>
</xsl:template>
</xsl:stylesheet>

<?xml-stylesheet type="text/xsl" href="data.xsl"?>
<items>
  <item id="A1">
    <item id="A2">
      <item id="A3" />
    </item>
  </item>
  <item id="B1">
    <item id="B2">
      <item id="B3" parentid="A2" />
    </item>
  </item>
</items>


--+------------------------------------------------------------------
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>
--+--