Subject: Re: targeting the last element in a node or consecutive elements
From: Chuck Bearden <cbearden@xxxxxxxx>
Date: Thu, 4 Jan 2007 16:00:04 -0600
|
Your second 'apply-templates' rule will omit text and comment nodes,
but that may not be important to your use case.
I adapted Jarno Elovirta's tree walking design pattern [1] for your
problem. It's rather verbose and probably overkill for your
problem, but you can see that this pattern of node-by-node walking
is quite powerful and can be adapted to many uses.
[1] http://www.dpawson.co.uk/xsl/sect2/N4486.html#d5280e1102
--------------------------------------------------------------------
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:output indent="yes" method="xml"/>
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="somenode">
<xsl:param name="nodeType">start</xsl:param>
<xsl:copy>
<xsl:apply-templates select="@*"/>
<!-- Step into 'walk' mode and process first child node -->
<xsl:apply-templates select="node()[1]" mode="walk">
<xsl:with-param name="nodeType" select="$nodeType"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<!-- 'walk' mode templates -->
<!-- 'walk' mode; PI with no elements in following-sibling axis -->
<xsl:template match="processing-instruction()
[not(following-sibling::*)]" mode="walk">
<xsl:param name="nodeType"/>
<xsl:if test="$nodeType='elem'">
<!-- We are in the first PI after the last element;
do any special processing here -->
<insertedElement/><xsl:text>
</xsl:text>
</xsl:if>
<!-- Apply default mode templates to this node -->
<xsl:apply-templates select="."/>
<!-- Walk on to next sibling node -->
<xsl:apply-templates select="following-sibling::node()[1]" mode="walk">
<xsl:with-param name="nodeType">pi</xsl:with-param>
</xsl:apply-templates>
</xsl:template>
<!-- 'walk' mode; all other nodes -->
<xsl:template match="node()" mode="walk">
<xsl:param name="nodeType"/>
<!-- Apply default mode templates to this node -->
<xsl:apply-templates select="."/>
<!-- Walk on to next sibling node -->
<xsl:apply-templates select="following-sibling::node()[1]" mode="walk">
<!-- Tell following templates which of element or pi was last seen -->
<xsl:with-param name="nodeType">
<xsl:choose>
<xsl:when test="self::*">elem</xsl:when>
<xsl:when test="self::processing-instruction()">pi</xsl:when>
<xsl:otherwise><xsl:value-of select="$nodeType"/></xsl:otherwise>
</xsl:choose>
</xsl:with-param>
</xsl:apply-templates>
</xsl:template>
<!-- Default mode templates; standard identity transforms -->
<xsl:template match="*">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|text()|comment()">
<xsl:copy/>
</xsl:template>
<xsl:template match="processing-instruction()">
<!-- Special treatment for PIs? -->
<xsl:copy/>
</xsl:template>
</xsl:stylesheet>
--------------------------------------------------------------------
Chuck
--
Chuck Bearden ---------------------------------- C o n n e x i o n s
Sr. Content Specialist Rice University MS 375
cbearden@xxxxxxxx PO Box 1892
AIM: Schleifheim Houston, TX 77251-1892
713.348.3661 (voice) --- <http://cnx.org/> ------ (fax) 713.348.3665
> From: egarrett@xxxxxxxxxxxx <egarrett@xxxxxxxxxxxx>
> Date: Jan 4, 2007 2:42 PM
> Subject: Re: targeting the last element in a node or consecutive
> elements
> To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
>
>
> This appears to be working:
>
> <xsl:apply-templates select="node()[not(self::processing-
> instruction()[not(following-sibling::*)])]"/>
>
> Then I insert the extra element. Then grab the PIs I suppressed above:
> <xsl:apply-templates select="node()[self::processing-
> instruction()[not(following-sibling::*)]]"/>
>
> Does it look right?
>
> Thanks.
> --emily
>
> ----- Original Message -----
> From: <egarrett@xxxxxxxxxxxx>
> Date: Thursday, January 4, 2007 2:21 pm
> Subject: Re: targeting the last element in a node or consecutive
> elements
> To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
>
> >Here is my logic so far to target everything in the node, and if
> >it is
> >a processing-instruction it should be processed only if something
> >exists after it other than another processing-instruction. What I
> >have
> >below does not work because I think it is looking for the second
> >processing-instruction inside the first one rather than following
> >it,
> >but it is starting to feel like it is possible to put what I need
> >in
> >one instruction.
> >
> ><xsl:apply-templates select="node()[not(self::processing-instruction()
> >[not(following::*[not(self::processing-instruction())])])]"/>
> >
> >Warning: on line 58 of file:/C:/Documents%20and%
> >20Settings/egarrett/Desktop/Transforms%20R%20Us/saxon/xsl/X3B.xsl:
> > The self axis will never select any element() nodes when
> >starting at
> >an
> > processing-instruction() node
> >
> >Any ideas?
> >----- Original Message -----
> >From: egarrett@xxxxxxxxxxxx
> >Date: Thursday, January 4, 2007 9:59 am
> >Subject: Re: targeting the last element in a node or
> >consecutive
> >elements
> >To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> >
> >> Yes, your example is correct. I don't know if or how many PIs
> >> will
> >> occur at the end of the node.
> >>
> >> P.S. I started a new post because they changed the
> >> requirements....
> >>
> >> ----- Original Message -----
> >> From: Abel Braaksma <abel.online@xxxxxxxxx>
> >> Date: Thursday, January 4, 2007 9:53 am
> >> Subject: Re: targeting the last element in a node or
> >> consecutive
> >> elements
> >> To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> >>
> >> > Hi Emily,
> >> >
> >> > This is a double post, you already opened this discussion
> >under
> >> > "suppressing only the last PI" (which differed in details,
> >however).> >
> >> > If I may, it appears that you want to do this:
> >> >
> >> > <somenode>
> >> > <node1 />
> >> > <?instr1?>
> >> > <node2 />
> >> > <?instr2?>
> >> > <?instr3?>
> >> > </somenode>
> >> >
> >> > 1. Process node1, instr1, node2 etc
> >> > 2. Do something before instr2 and instr3 (being consecutively
> >> and
> >> > together at the end of a node)
> >> > 3. Process instr2 and instr3
> >> > (if instr2 and instr3 were not there, you want to skip
> >> processing
> >> > step 2
> >> > and 3?)
> >> >
> >> > Am i right? Please confirm (and/or give your sample input, to
> >> make
> >> > the
> >> > subject easier)
> >> >
> >> > Cheers,
> >> > -- Abel
> >> >
> >> > Emily.Garrett@xxxxxxxxxxx wrote:
> >> > > I'm trying to use xsl:apply templates to grab the entire
> >> content
> >> > of a
> >> > > node, except for any PIs that may be at the very end of the
> >> > node. I can
> >> > > see how position()=last() can be used to refer to the very
> >> last
> >> > PI, but
> >> > > how would I refer to possibly 2 or 3 PIs that are at the end
> >> of
> >> > the node
> >> > > (not knowing what they are or how many), but still process
> >PIs
> >> > that are
> >> > > contained elsewhere in this content? Is there some syntax
> >> that
> >> > refers> to consecutive elements or refers to an element that
> >is
> >> > the last one in
> >> > > a node, not knowing what element it is?
> >> > >
> >> > > Here is explanation for what I'm trying to do:
> >> > >
> >> > > Process all content, unless they are PIs that occur
> >> > consecutively at the
> >> > > very end of the node.
> >> > >
> >> > > Then I have to insert an element, then process these PIs
> >that
> >> occur> > consecutively at the very end of the node.
> >> > >
> >> > > I'm having trouble narrowing down my research on this one.
> >> Does
> >> > anyone> have any ideas?
> >> > >
> >> > > Thanks,
> >> > > Emily
|