Subject: FW: [xsl] [XSL] extracting a verse From: "Conal Tuohy" <conalt@xxxxxxxxxxxxxxx> Date: Mon, 23 Dec 2002 13:25:45 +1300 |
I posted this message on Sunday but it hasn't appeared yet. Sorry if you see this twice: -----Original Message----- From: Conal Tuohy [mailto:conalt@xxxxxxxxxxxxxxx] Sent: Sunday, 22 December 2002 17:43 To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx Subject: RE: [xsl] [XSL] extracting a verse Here's a style-sheet I wrote to do this kind of thing. I'm a bit embarrassed to post it because it's klunky and not really generalized (it was done in a rush and never optimized) but it does the trick. This was actually used in a pipelined process (inside Cocoon) to process some TEI documents prior to feeding them into another suite of TEI-processing stylesheets. I had to preserve <pb/> (page breaks) in the TEI which can fall in the middle of someone's name, inside an item inside a list, etc... I didn't want to edit the suite of stylesheets because it would have required reading and making small changes to dozens of complex existing templates, so instead I used this stylesheet to "promote" the <pb/> elements and split the <name>, <item>, <list> etc, etc, elements where necessary. Because it's a stage in a pipeline, it simply copies each partition with <xsl:copy> and <xsl:copy-of>, but it could easily be modified to work in a non-pipelined environment by using <apply-templates mode="process-partition"> to process each partitioned "range" of the document (i.e. each bible verse, in the example under discussion). Cheers! Con <!-- make-partitions.xsl Implements a kind of "dismemberment" transformation to a document. It copies the document, while dismembering certain parts. To use, call the template "make-partitions" with context node being the node to partition. Specify the list of delimiters using the "delimiters" nodeset parameter. The nodes in this set should all be descendants of the context node. If the context node has n delimiters it will be copied n+1 times, each copy containing the tree of descendants between each delimiter. In between the n+1 copies will be the delimiters themselves, which will have become siblings of the node that was originally their ancestor. e.g. to move <hr> elements out from inside <p> elements up to the same level: <xsl:template match="p"> <xsl:call-template name="make-partitions"> <xsl:with-param name="delimiters" select=".//hr"/> </xsl:call-template> </xsl:template> This will transform the following fragment: <p> Blah blah blah <hr/> blah blah <i> blah blah <hr/> blah blah </i> blah. </p> <p> Blah blah blah </p> <hr/> <p> blah blah <i> blah blah </i> </p> <hr/> <p> <i> blah blah </i> blah. </p> --> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="*" mode="get-partition"> <xsl:param name="start-delimiter-id"/> <xsl:param name="end-delimiter-id"/> <xsl:variable name="parent" select="."/> <xsl:variable name="start-delimiter-pos"> <xsl:call-template name="get-delimiter-position"> <xsl:with-param name="delimiter-id" select="$start-delimiter-id"/> <xsl:with-param name="context-list" select="$parent/node()"/> </xsl:call-template> </xsl:variable> <xsl:variable name="end-delimiter-pos"> <xsl:call-template name="get-delimiter-position"> <xsl:with-param name="delimiter-id" select="$end-delimiter-id"/> <xsl:with-param name="context-list" select="$parent/node()"/> </xsl:call-template> </xsl:variable> <xsl:choose> <xsl:when test="$end-delimiter-pos > 0 or $start-delimiter-pos > 0"> <!-- at least one of the delimiters is present --> <xsl:copy> <xsl:copy-of select="@*"/> <xsl:choose><!-- how to partition the children --> <xsl:when test="$start-delimiter-pos > 0 and $end-delimiter-pos=$start-delimiter-pos"> <!-- delimiters are both children of the same child of the current node --> <!-- recurse, and allow this child node to partition itself --> <xsl:apply-templates mode="get-partition" select="$parent/node()[position()=$start-delimiter-pos]"> <xsl:with-param name="start-delimiter-id" select="$start-delimiter-id"/> <xsl:with-param name="end-delimiter-id" select="$end-delimiter-id"/> </xsl:apply-templates> </xsl:when> <xsl:otherwise> <!-- delimiters are not contained entirely within a child of the current node --> <!-- is start-delimiter inside a child? --> <xsl:if test="$start-delimiter-pos > 0"> <xsl:if test="not($parent/node()[generate-id()=$start-delimiter-id])"> <xsl:apply-templates mode="get-partition" select="$parent/node()[position()=$start-delimiter-pos]"> <xsl:with-param name="start-delimiter-id" select="$start-delimiter-id"/> <xsl:with-param name="end-delimiter-id" select="$end-delimiter-id"/> </xsl:apply-templates> </xsl:if> </xsl:if> <!-- handle any children between delimiters or between children containing delimiters --> <xsl:choose> <xsl:when test="$end-delimiter-pos>0"> <xsl:copy-of select="$parent/node()[position() > $start-delimiter-pos and $end-delimiter-pos > position()]"/> </xsl:when> <xsl:otherwise> <xsl:copy-of select="$parent/node()[position() > $start-delimiter-pos]"/> </xsl:otherwise> </xsl:choose> <!-- is end-delimiter inside a child? --> <xsl:if test="$end-delimiter-pos > 0"> <xsl:if test="not($parent/node()[generate-id()=$end-delimiter-id])"> <xsl:apply-templates mode="get-partition" select="$parent/node()[position()=$end-delimiter-pos]"> <xsl:with-param name="start-delimiter-id" select="$start-delimiter-id"/> <xsl:with-param name="end-delimiter-id" select="$end-delimiter-id"/> </xsl:apply-templates> </xsl:if> </xsl:if> </xsl:otherwise> </xsl:choose> </xsl:copy> </xsl:when> <xsl:otherwise> <!-- no delimiters present - use copy-of to copy this sub-tree --> <xsl:copy-of select="."/> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template name="get-delimiter-position"> <xsl:param name="delimiter-id"/> <xsl:param name="context-list"/> <xsl:variable name="position"> <xsl:for-each select="$context-list"> <xsl:variable name="current-position" select="position()"/> <xsl:choose> <xsl:when test="generate-id(.)=$delimiter-id"> <xsl:value-of select="$current-position"/> </xsl:when> <xsl:when test=".//*[generate-id(.)=$delimiter-id]"> <xsl:value-of select="$current-position"/> </xsl:when> </xsl:choose> </xsl:for-each> </xsl:variable> <xsl:choose> <xsl:when test="$position>0"> <xsl:value-of select="$position"/> </xsl:when> <xsl:otherwise><xsl:value-of select="0"/></xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template name="make-partitions"> <!-- if the element contains delimiters, partition it, otherwise, copy it --> <xsl:param name="delimiters"/> <xsl:variable name="current-node" select="."/> <xsl:choose> <xsl:when test="$delimiters"> <!-- the current element includes children which should partition it --> <xsl:variable name="context-list" select="./node()"/> <!-- get the first partition --> <xsl:variable name="first-partition-delimiter-id" select="generate-id($delimiters[position()=1])"/> <xsl:apply-templates mode="get-partition" select="."> <xsl:with-param name="end-delimiter-id" select="$first-partition-delimiter-id"/> </xsl:apply-templates> <!-- copy the delimiter itself --> <xsl:copy-of select="$delimiters[position()=1]"/> <!-- intermediate partitions --> <xsl:for-each select="$delimiters"> <!-- do all except the final partition, which must have no end-delimiter --> <xsl:if test="position()>1"> <xsl:variable name="start-delimiter-index" select="position()-1"/> <xsl:variable name="start-delimiter-id" select="generate-id($delimiters[position()=$start-delimiter-index])"/> <xsl:apply-templates mode="get-partition" select="$current-node"> <xsl:with-param name="start-delimiter-id" select="$start-delimiter-id"/> <xsl:with-param name="end-delimiter-id" select="generate-id(.)"/> </xsl:apply-templates> <!-- copy the delimiter itself --> <xsl:copy-of select="."/> </xsl:if> </xsl:for-each> <!-- final partition --> <xsl:apply-templates mode="get-partition" select="."> <xsl:with-param name="start-delimiter-id" select="generate-id($delimiters[position()=last()])"/> </xsl:apply-templates> </xsl:when> <xsl:otherwise> <!-- contains no delimiters - just copy the element normally --> <xsl:copy-of select="."/> </xsl:otherwise> </xsl:choose> </xsl:template> <!-- identity transformation otherwise --> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet> XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
RE: [xsl] [XSL] extracting a verse, Jim_Albright | Thread | [xsl] White space required b/w publ, Denis Nwanshi |
[no subject], Raheem Rufai | Date | [xsl] XForms processor, cknell |
Month |