|
[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message] Re: String replacement in included content
David,
Your suggestion of doing this transformation in 2 passes was brilliant. I have the whole thing working now, and it didn't require too much code or change to the existing stylesheet. A couple of global variables: <!-- At the outermost level, we want an empty replace string and a proper search string --> <xsl:variable name="globalFind"> <str>%CT%</str> </xsl:variable> <xsl:variable name="globalReplace"> <rep></rep> </xsl:variable> My component match template (I haven't edited it, these things are really called <imlcomponent>: <xsl:template priority="1.0" match="//imlcomponent"> <xsl:variable name="componentFilename"> <xsl:value-of select="@href" /> </xsl:variable> <xsl:variable name="repl"> <xsl:choose> <xsl:when test="@tag"> <rep><xsl:value-of select="@tag" /></rep> </xsl:when> <xsl:otherwise> <!-- No tag is equivalent to removing all occurrences of %CT% --> <rep></rep> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:choose> <!-- The cases where we never expand the imlcomponent --> <xsl:when test="ancestor::imltemplatehead or ancestor::imlheadcontentinsert"> <xsl:if test="$v='y'"><xsl:comment> imlcomponent is NEVER expanded inside imltemplatehead. Just copy element.</xsl:comment></xsl:if> <xsl:copy-of select="." /> </xsl:when> <!-- In all other cases we will bring in the right content from the component file --> <xsl:otherwise> <xsl:choose> <!-- Decide what mode we need to use for the template processing --> <xsl:when test="ancestor::form or $templateBodyContentIsInsideForm != ''"> <!-- The form//include case --> <xsl:if test="$v='y'"><xsl:comment> imlcomponent inside a form: Replace with all body/form content of: <xsl:value-of select="$componentFilename" /></xsl:comment></xsl:if> <xsl:variable name="textReplacedContents"> <xsl:apply-templates select="document(string($componentFilename))//body/form/*" mode="r"> <xsl:with-param name="replace" select="exslt:node-set($repl)" /> </xsl:apply-templates> </xsl:variable> <xsl:apply-templates select="exslt:node-set($textReplacedContents)" /> </xsl:when> <xsl:otherwise> <!-- The include case outside of a form --> <xsl:if test="$v='y'"><xsl:comment> imlcomponent outside a form: Replace with body element content of: <xsl:value-of select="$componentFilename" />, excluding all imltemplate elements.</xsl:comment></xsl:if> <xsl:variable name="textReplacedContents"> <xsl:apply-templates select="document(string($componentFilename))//body/*[not(local-name()='imltemplate')]" mode="r"> <xsl:with-param name="replace" select="exslt:node-set($repl)" /> </xsl:apply-templates> </xsl:variable> <xsl:apply-templates select="exslt:node-set($textReplacedContents)" /> </xsl:otherwise> </xsl:choose> </xsl:otherwise> </xsl:choose> </xsl:template> The key here was to apply the text replacement templates first to the node set, then to apply-templates to it. The replacement templates: <!--======================================================================================= Template for processing a non-text node. Replaces all occurrences of the search string terms in the element's attribute values with their corresponding replacement text, then recursively processes all children for the same text replacement. ========================================================================================--> <xsl:template match="node()" mode="r"> <xsl:comment>Template match for node() mode="r"</xsl:comment> <xsl:param name="search" select="exslt:node-set($globalFind)" /> <xsl:param name="replace" select="exslt:node-set($globalReplace)" /> <xsl:copy> <!-- String replacement for each attribute value --> <xsl:for-each select="@*"> <xsl:attribute name="{name()}"> <xsl:call-template name="str:replace"> <xsl:with-param name="string" select="string(.)" /> <xsl:with-param name="search" select="$search" /> <xsl:with-param name="replace" select="$replace" /> </xsl:call-template> </xsl:attribute> </xsl:for-each> <!-- Recurse over children --> <xsl:apply-templates select="node()" mode="r"> <xsl:with-param name="search" select="$search" /> <xsl:with-param name="replace" select="$replace" /> </xsl:apply-templates> </xsl:copy> </xsl:template> <!--======================================================================================= Template for processing a text node. Replaces all occurrences of the search string terms in the text string with their corresponding replacement text. ========================================================================================--> <xsl:template match="text()" mode="r"> <xsl:comment>Template match for text() mode="r"</xsl:comment> <xsl:param name="search" select="exslt:node-set($globalFind)" /> <xsl:param name="replace" select="exslt:node-set($globalReplace)" /> <xsl:variable name="x"> <xsl:value-of select="." /> </xsl:variable> <xsl:call-template name="str:replace"> <xsl:with-param name="string" select="$x" /> <xsl:with-param name="search" select="$search" /> <xsl:with-param name="replace" select="$replace" /> </xsl:call-template> </xsl:template> This took care of the included components. To handle the case where a document can be used as either a component or a top level doc, I needed to find a way to do the equivalent transformation on the top level doc. I already had a template that matched a naked <HTML> element (which all of my documents contain), so I added the processing there: <xsl:template match="html[not(@xmlns)]"> <!-- Do string replacement on all children --> <xsl:variable name="temp"> <xsl:apply-templates select="@*|node()" mode="r"> </xsl:apply-templates> </xsl:variable> <!-- transform the html element as required --> <xsl:element name="{name()}"> <xsl:attribute name="xmlns"> <xsl:text>http://www.w3.org/1999/xhtml</xsl:text> </xsl:attribute> <xsl:copy-of select="@*" /> <!-- Process the text replaced nodeset --> <xsl:apply-templates select="exslt:node-set($temp)" /> </xsl:element> </xsl:template> There's probably a better way to handle this, but the things I tried didn't work. I think that's everything that is relevant. Now I can handle: <imlcomponent href="file" /> <imlcomponent href="file" tag="" /> <imlcomponent href="file" tag="FixedTag"> <imlcomponent href="file" tag="%CT%_AddedTag" /> where the last version allows me to "chain" the tags through a series of nested includes. Very cool. Thank you again for your help. I would have flopped around for a long time without it. Best regards, Rush
|
PURCHASE STYLUS STUDIO ONLINE TODAY!Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced! Download The World's Best XML IDE!Accelerate XML development with our award-winning XML IDE - Download a free trial today! Subscribe in XML format
|

Cart








