Dear Newsgroup I have an input XHTML document containing multiple topics. It contains topic names in h1 tags followed by content elements at the same level, and I want the transform to be able to select a single topic as specified by a parameter and output the topic as valid XHTML. I'm OK with the parameter but I cannot figure out how to get just the topic I want. Here is the input: ------- input2.xhtml -------- <?xml version="1.0"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> <head> <title>Fruits</title> </head> <body> <h1>Apples</h1> <p>Round fruits that grow on trees.</p> <p>They taste OK.</p> <h1>Bananas</h1> <p>Yellow fruits that grow in clumps.</p> <p>They taste nice as a smoothie.</p> <h1>Turnips</h1> <p>Warty vegetable, OK if roasted.</p> </body> </html> ------- input2.xhtml -------- ------- transform2.xslt --------- <xsl:stylesheet version="1.0" xmlns="http://www.w3.org/1999/xhtml" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xhtml="http://www.w3.org/1999/xhtml" exclude-result-prefixes="xhtml xsl"> <xsl:output method="xml" indent="yes" omit-xml-declaration="yes" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"/> <xsl:param name="title"/> <xsl:variable name="first">4</xsl:variable> <xsl:variable name="last">6</xsl:variable> <xsl:template match="/"> <html> <head> <title> <xsl:value-of select="$title"/> </title> </head> <body> <xsl:for-each select="xhtml:html//xhtml:h1|xhtml:html//xhtml:p"> <xsl:if test="position() >= $first and position() <= $last"> <xsl:copy-of select="."></xsl:copy-of> </xsl:if> </xsl:for-each> </body> </html> </xsl:template> </xsl:stylesheet> ------- transform2.xslt --------- ---- wanted-output.xhtml ----- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Bananas</title> </head> <body> <h1>Bananas</h1> <p>Yellow fruits that grow in clumps.</p> <p>They taste nice as a smoothie.</p> </body> </html> ---- wanted-output.xhtml ----- In this case I pass in "Bananas" as the 'title' parameter and I want my output to be just the topic associated with Bananas (eg the position() between 4 and 6). But the only way I can make it work is by hard-wiring the 'first' and 'last' position values which is not useful :) In my transform I want something like: <xsl:variable name="first" select="position-of(text()=$title)"/> <xsl:variable name="last" select="position-of(text()=$title) and position() > $first"/> But somehow I don't think that will work :) Any pointers would be welcome. Kind regards, Will Rayer
William Rayer wrote: > But somehow I don't think that will work :) Any pointers would be welcome. Here is how I would solve that: <xsl:stylesheet version="1.0" xmlns="http://www.w3.org/1999/xhtml" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xhtml="http://www.w3.org/1999/xhtml" exclude-result-prefixes="xhtml xsl"> <xsl:output method="xml" indent="no" omit-xml-declaration="yes" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"/> <xsl:param name="title"/> <xsl:template match="@* | node()"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:template> <xsl:template match="xhtml:h1"> <xsl:if test=". = $title"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:if> </xsl:template> <xsl:template match="xhtml:p"> <xsl:if test="preceding-sibling::xhtml:h1[1] = $title"> <xsl:copy> <xsl:apply-templates select="@* | node()"/> </xsl:copy> </xsl:if> </xsl:template> </xsl:stylesheet> -- Martin Honnen --- MVP XML http://JavaScript.FAQTs.com/
Hi Martin Many thanks - that seems to work fine! But is it possible to do it from within the context of a single template match on the root node? I am trying to keep the HTML output in the form: <xsl:template match="/"> <html> <head> <title> <xsl:value-of select="$title"/> </title> </head> <body> <!-- XSLT stuff in here --> </body> </html> </xsl:template> as I find this easier to understand.?
William Rayer wrote: > Many thanks - that seems to work fine! But is it possible to do it from > within the context of a single template match on the root node? I am trying > to keep the HTML output in the form: > > <xsl:template match="/"> > <html> > <head> > <title> <xsl:value-of select="$title"/> </title> > </head> > <body> > > <!-- XSLT stuff in here --> > > </body> > </html> > </xsl:template> > > as I find this easier to understand.? Well using the identity transformation template and adding templates to perform some changes is a fundamental XSLT approach you should try to become familiar with. If you really insist on one template and spelling out the structure again instead of simply copying it then you need <xsl:stylesheet version="1.0" xmlns="http://www.w3.org/1999/xhtml" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xhtml="http://www.w3.org/1999/xhtml" exclude-result-prefixes="xhtml xsl"> <xsl:output method="xml" indent="yes" omit-xml-declaration="yes" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"/> <xsl:param name="title"/> <xsl:variable name="h1" select="/xhtml:html/xhtml:body/xhtml:h1[. = $title]"/> <xsl:template match="/"> <html> <head> <title> <xsl:value-of select="$title"/> </title> </head> <body> <xsl:copy-of select="$h1 | $h1/following-sibling::xhtml:p[generate-id($h1) = generate-id(preceding-sibling::xhtml:h1[1])]"/> </body> </html> </xsl:template> </xsl:stylesheet> -- Martin Honnen --- MVP XML http://JavaScript.FAQTs.com/
Hi Martin That is really neat - & even better it works :) I really appreciate you showing me this. BTW I was also very interested by what you wrote: > ... adding templates to > perform some changes is a fundamental XSLT approach you should try to > become familiar with. I had to get to grips with XSLT about a year ago. Although I'm happy with most development tasks (C, C#, SQL etc) I found it very difficult to get to grips with transforms. I found this article <http://www.xfront.com/rescuing-xslt.html> which was written by soneone with the same issues (programming experience but problems getting to grips with transforms). His insight (to me) was to treat XSLT as a powerful templating language, allowing me to embed the desired HTML output in the XSLT and to treat the <xsl...> instructions as special tags that get values from the input XML. Anyway sorry to go on but I found XSLT much easier when following the 'template' approach. I understand it may be non-ideal and I may need to expand my XSLT later on. Thanks again - Will Rayer "Martin Honnen" wrote: > William Rayer wrote: > > > Many thanks - that seems to work fine! But is it possible to do it from > > within the context of a single template match on the root node? I am trying > > to keep the HTML output in the form: > > > > <xsl:template match="/"> > > <html> > > <head> > > <title> <xsl:value-of select="$title"/> </title> > > </head> > > <body> > > > > <!-- XSLT stuff in here --> > > > > </body> > > </html> > > </xsl:template> > > > > as I find this easier to understand.? > > Well using the identity transformation template and adding templates to > perform some changes is a fundamental XSLT approach you should try to > become familiar with. > > If you really insist on one template and spelling out the structure > again instead of simply copying it then you need > > > <xsl:stylesheet version="1.0" > xmlns="http://www.w3.org/1999/xhtml" > xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > xmlns:xhtml="http://www.w3.org/1999/xhtml" > exclude-result-prefixes="xhtml xsl"> > > <xsl:output method="xml" indent="yes" omit-xml-declaration="yes" > doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" > > doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"/> > > <xsl:param name="title"/> > > <xsl:variable name="h1" select="/xhtml:html/xhtml:body/xhtml:h1[. = > $title]"/> > > <xsl:template match="/"> > <html> > <head> > <title> <xsl:value-of select="$title"/> </title> > </head> > <body> > > <xsl:copy-of select="$h1 | > $h1/following-sibling::xhtml:p[generate-id($h1) = > generate-id(preceding-sibling::xhtml:h1[1])]"/> > > </body> > </html> > </xsl:template> > > </xsl:stylesheet> > > > > > -- > > Martin Honnen --- MVP XML > http://JavaScript.FAQTs.com/ >