We have a program that uses xml to save configurations of our program. Someone decided to rename a couple of values in our database and these renames should now also be backwards compatible in the configurations of our customers.
An example of a configuration
<configuration>
<fruitToEat>yellow_curved_thing</fruitToEat> <!-- should now become banana -->
</configuration>
A simple match would be (not tested, just an example):
<xsl:template>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match"/configuration/fruitToEat/text()">
<xsl:text>banana</xsl:text>
</xsl:template>
</xsl:template>
But this is just one example and I want to do this 150 times.
Is it possible to make an xsl that reads a simple text file or ini file that tells me how the 150 matches should look alike?
<xsl:template>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<!-- recreate this template 150 times from an ini file or something -->
<xsl:template match"/configuration/fruitToEat/text()[.='yellow_curved_thing']">
<xsl:text>banana</xsl:text>
</xsl:template>
</xsl:template>
An example of my mapping file could be simply:
yellow_curved_thing = banana
round_thing = tomato
round_dotted = strawberry
And I would simply want a small xslt that tells me:
<xsl:template>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<!-- recreate this template 150 times from an ini file or something -->
<xsl:template match"/configuration/fruitToEat/text()[.=$fileRow0]">
<xsl:text>$fileRow1</xsl:text>
</xsl:template>
</xsl:template>
So even if I think there is more complexity behind the curtain, may be this will help a little bit.
There are some possibilities to do this with xlst. Which would be best in long term depends on complexity in real life and how often you need to do this with different "mapping" information.
For your easy example you can put the "mapping" information into a xml file. This could be done by some script form ini file.
<mappings>
<mapping name="fruitToEat" >
<map from="yellow_curved_thing" to="banana" />
<map from="round_thing" to="tomato" />
<map from="round_dotted" to="strawberry" />
</mapping>
</mappings>
Than you can have a template which make use of this mapping information:
<xsl:variable name="fruitMapping"
select="document('fruitmapping.xml')//mapping[#name='fruitToEat']" />
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/configuration/fruitToEat/text()" >
<!-- find the entry in "ini file" -->
<xsl:variable name ="map" select="$fruitMapping/map[#from = current()]" />
<xsl:choose>
<xsl:when test="$map" >
<xsl:value-of select="$map/#to"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
But if this is a onetime job I would implement this "mapping" direct a template. Like this:
<xsl:template match="/configuration/fruitToEat/text()" >
<xsl:choose>
<xsl:when test=".='yellow_curved_thing'" >banana</xsl:when>
<xsl:when test=".='round_thing'" >tomato</xsl:when>
<xsl:when test=".='round_dotted'" >strawberry</xsl:when>
<xsl:otherwise>
<xsl:copy />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
It seems you wanted to create your XSLT dynamic XSLT on the basis of your configuration file which is also an XML document. Have a look this exmple considering this:
configuration.xml
<p>
<configuration>
<fruitToEat>yellow_curved_thing</fruitToEat>
<mapped>banana</mapped>
</configuration>
<configuration>
<fruitToEat>round_thing</fruitToEat>
<mapped>tomato</mapped>
</configuration>
</p>
XSLT:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" encoding="UTF-8" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="/">
<xsl:element name="xsl:stylesheet">
<xsl:attribute name="version">
<xsl:text>1.0</xsl:text>
</xsl:attribute>
<xsl:element name="xsl:template">
<xsl:attribute name="match">
<xsl:text>node()|#*</xsl:text>
</xsl:attribute>
<xsl:element name="xsl:copy">
<xsl:element name="xsl:apply-templates">
<xsl:attribute name="select">
<xsl:text>node()|#*</xsl:text>
</xsl:attribute>
</xsl:element>
</xsl:element>
</xsl:element>
<xsl:for-each select="//configuration">
<xsl:element name="xsl:template">
<xsl:attribute name="match">
<xsl:text>configuration/fruitToEat/text()[.=</xsl:text>
<xsl:text>'</xsl:text>
<xsl:value-of select="fruitToEat"/>
<xsl:text>']</xsl:text>
</xsl:attribute>
<xsl:element name="xsl:text">
<xsl:value-of select="mapped"/>
</xsl:element>
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
output:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="configuration/fruitToEat/text()[.='yellow_curved_thing']">
<xsl:text>banana</xsl:text>
</xsl:template>
<xsl:template match="configuration/fruitToEat/text()[.='round_thing']">
<xsl:text>tomato</xsl:text>
</xsl:template>
</xsl:stylesheet>
Related
I changed now multiple times my xsl, but I didn't find the right way. Now here is what I want:
I try to find now all missing Pages, which got no description. If it's missing, I want to add a description for that page, if it exist, I want to modify the Description. The String for pageX to pageXDescription is always the same.
Here is my short example xml:
<BOOK>
<PAGE NAME='page1' VALUE='coolText'/>
<PAGE NAME='Description1' VALUE='coolDescription'/>
<PAGE NAME='page2' VALUE='moreText'/>
<PAGE NAME='page3' VALUE='aLotMoreText'/>
<PAGE NAME='Description3' VALUE='aLotMoreDescriptions'/>
</BOOK>
I tried it with something like that:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- define output settings and header -->
<xsl:output method="xml" indent="yes" omit-xml-declaration="no" media-type="string" encoding="ISO-8859-1" doctype-system="deftable.dtd"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="BOOK[PAGE/#NAME='page1']">
<xsl:copy>
<xsl:call-template name="create_missing_description_pages">
<xsl:with-param name="page" select="'page1'"/>
<xsl:with-param name="description" select="'Description1'"/>
<xsl:with-param name="new_description" select="'newContent'"/>
</xsl:call-template>
</xsl:copy>
</xsl:template>
<xsl:template match="BOOK[PAGE/#NAME='page2']">
<xsl:copy>
<xsl:call-template name="create_missing_description_pages">
<xsl:with-param name="page" select="'page2'"/>
<xsl:with-param name="description" select="'Description2'"/>
<xsl:with-param name="new_description" select="'newContent'"/>
</xsl:call-template>
</xsl:copy>
</xsl:template>
<xsl:template match="BOOK[PAGE/#NAME='page3']">
<xsl:copy>
<xsl:call-template name="create_missing_description_pages">
<xsl:with-param name="page" select="'page3'"/>
<xsl:with-param name="description" select="'Description3'"/>
<xsl:with-param name="new_description" select="'newContent'"/>
</xsl:call-template>
</xsl:copy>
</xsl:template>
<!-- Function to generate missing XML Tags -->
<xsl:template name="create_missing_description_pages">
<xsl:param name="page"/>
<xsl:param name="description"/>
<xsl:param name="new_description"/>
<xsl:apply-templates select="#*|VARIABLE[#NAME=$page]/preceding-sibling::node()"/>
<xsl:apply-templates select="VARIABLE[#NAME=$page]"/>
<xsl:if test="not(VARIABLE/#NAME=$description)">
<xsl:element name="PAGE">
<xsl:attribute name="NAME"><xsl:value-of select="$description"/></xsl:attribute>
<xsl:attribute name="VALUE"><xsl:value-of select="$new_description"/></xsl:attribute>
</xsl:element>
</xsl:if>
<xsl:apply-templates select="VARIABLE[#NAME=$page]/following-sibling::node()"/>
</xsl:template>
<xsl:template match="BOOK/PAGE">
<xsl:copy>
<xsl:choose>
<xsl:when test="#NAME='Description1'">
<xsl:attribute name="NAME"><xsl:value-of select="#NAME"/></xsl:attribute>
<xsl:attribute name="VALUE">newContent</xsl:attribute>
</xsl:when>
<xsl:when test="#NAME='Description2'">
<xsl:attribute name="NAME"><xsl:value-of select="#NAME"/></xsl:attribute>
<xsl:attribute name="VALUE">newContent</xsl:attribute>
</xsl:when>
<xsl:when test="#NAME='page3Description'">
<xsl:attribute name="NAME"><xsl:value-of select="#NAME"/></xsl:attribute>
<xsl:attribute name="VALUE">newContent</xsl:attribute>
</xsl:when>
<!-- other child items will just be copied -->
<xsl:otherwise>
<xsl:copy-of select="#*"/>
</xsl:otherwise>
</xsl:choose>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
That is what I'm expecting in all cases, if all Descriptions are missing, or if all Descriptions are available:
<BOOK>
<PAGE NAME='page1' VALUE='coolText'/>
<PAGE NAME='Description1' VALUE='newContent'/>
<PAGE NAME='page2' VALUE='moreText'/>
<PAGE NAME='Description2' VALUE='newContent'/>
<PAGE NAME='page3' VALUE='aLotMoreText'/>
<PAGE NAME='Description3' VALUE='newContent'/>
</BOOK>
If there is no page3, then I want also no page Description.
I hope so, that it's understandable.
Thanks a lot for a hint, where my logical failure is and how to fix it.
Best regards
Björn
Couldn't you make this simply:
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="PAGE">
<xsl:variable name="pagenum" select="xs:integer(substring-after(#NAME, 'page'))" />
<xsl:copy-of select="."/>
<PAGE NAME='Description{$pagenum}'>
<xsl:attribute name="VALUE">
<xsl:choose>
<xsl:when test="$pagenum=1">newContent1</xsl:when>
<xsl:when test="$pagenum=2">newContent2</xsl:when>
<xsl:when test="$pagenum=3">newContent3</xsl:when>
</xsl:choose>
</xsl:attribute>
</PAGE>
</xsl:template>
<xsl:template match="PAGE[starts-with(#NAME, 'Description')]"/>
</xsl:stylesheet>
With XSLT 2.0, I am trying to create a list of relations between all children of given elements, in a document such as:
<doc>
<part1>
<name>John</name>
<name>Paul</name>
<name>George</name>
<name>Ringo</name>
<place>Liverpool</place>
</part1>
<part2>
<name>Romeo</name>
<name>Romeo</name>
<name>Juliet</name>
<fam>Montague</fam>
<fam>Capulet</fam>
</part2>
</doc>
The result I would like to obtain, ideally by conflating and weighing the identical relations, would be (in whatever order) something like:
<doc>
<part1>
<rel><name>John</name><name>Paul</name></rel>
<rel><name>John</name><name>George</name></rel>
<rel><name>John</name><name>Ringo</name></rel>
<rel><name>Paul</name><name>George</name></rel>
<rel><name>Paul</name><name>Ringo</name></rel>
<rel><name>George</name><name>Ringo</name></rel>
<rel><name>John</name><place>Liverpool</place></rel>
<rel><name>Paul</name><place>Liverpool</place></rel>
<rel><name>George</name><place>Liverpool</place></rel>
<rel><name>Ringo</name><place>Liverpool</place></rel>
</part1>
<part2>
<rel weight="2"><name>Romeo</name><name>Juliet</name></rel>
<rel weight="2"><name>Romeo</name><fam>Montague</fam></rel>
<rel weight="2"><name>Romeo</name><fam>Capulet</fam></rel>
<rel><name>Juliet</name><fam>Montague</fam></rel>
<rel><name>Juliet</name><fam>Capulet</fam></rel>
<rel><fam>Montague</fam><fam>Capulet</fam></rel>
</part2>
</doc>
—but I'm not sure how to proceed. Many thanks in advance for your help.
You still haven't explained the logic that needs to be applied here, so this is based largely on a guess:
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="/">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="doc/*">
<!-- first pass-->
<xsl:variable name="unique-items">
<xsl:for-each-group select="*" group-by="concat(name(), '|', .)">
<item name="{name()}" count="{count(current-group())}" value="{.}"/>
</xsl:for-each-group>
</xsl:variable>
<!-- output -->
<xsl:copy>
<xsl:for-each select="$unique-items/item">
<xsl:variable name="left" select="."/>
<xsl:for-each select="following-sibling::item">
<xsl:variable name="weight" select="$left/#count * #count" />
<rel>
<xsl:if test="$weight gt 1">
<xsl:attribute name="weight" select="$weight"/>
</xsl:if>
<xsl:apply-templates select="$left | ." />
</rel>
</xsl:for-each>
</xsl:for-each>
</xsl:copy>
</xsl:template>
<xsl:template match="item">
<xsl:element name="{#name}">
<xsl:value-of select="#value"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
The idea here is to remove duplicates in the first pass, then enumerate all combinations in the second (final) pass. The weight is computed by multiplying the number of occurrences of each member of a combination pair and shown only when it exceeds 1.
At least the combinatoric part of your problem could be solved with the following XSLT script. It does not solve the elimination of duplicates, but that could possibly be done in a second transformation.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- standard copy template -->
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*" />
</xsl:copy>
</xsl:template>
<xsl:template match="doc/*">
<xsl:copy>
<xsl:variable name="l" select="./*"/>
<xsl:for-each select="$l">
<xsl:variable name="a" select="."/>
<xsl:variable name="posa" select="position()"/>
<xsl:variable name="namea" select="name()"/>
<xsl:for-each select="$l">
<xsl:if test="position() > $posa and (. != $a or name() != $namea)">
<rel>
<xsl:copy-of select="$a"/>
<xsl:copy-of select="."/>
</rel>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
When applied to the first part of your example, this produces:
<part1>
<rel><name>John</name><name>Paul</name></rel>
<rel><name>John</name><name>George</name></rel>
<rel><name>John</name><name>Ringo</name></rel>
<rel><name>John</name><place>Liverpool</place></rel>
<rel><name>Paul</name><name>George</name></rel>
<rel><name>Paul</name><name>Ringo</name></rel>
<rel><name>Paul</name><place>Liverpool</place></rel>
<rel><name>George</name><name>Ringo</name></rel>
<rel><name>George</name><place>Liverpool</place></rel>
<rel><name>Ringo</name><place>Liverpool</place></rel>
</part1>
Which seems about correct. If have no idea if the duplicate elimination (or weighting, as you call it) could be done in the same transformation.
I have two types of input xml, one with namespace prefix and another one without prefix and i want to replace the namespaces.
Sample1
<v1:Library xmlns:v1="http://testlibrary" xmlns:v2="http://commonprice">
<v1:Books_details>
<v1:Name>test1</v1:Name>
<v1:title>test2</v1:title>
<v2:price xmlns="http://commonprice">12</v2:price>
</v1:Books_details>
</v1:Library>
Sample2
<Library xmlns="http://testlibrary">
<Books_details>
<Name>test1</Name>
<title>test2</title>
<price xmlns="http://commonprice">12</price>
</Books_details>
</Library>
I have written following XSLT to change the namespace from "http://testlibrary" to "http://newlibrary" and it works fine for sample1 but it doesn't work for the sample2. It gives wrong result. It also the change the namespace of the price element even though it doesn't have namespace to be replaced.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:param name="old_namespace"/>
<xsl:param name="new_namespace"/>
<xsl:template match="/">
<xsl:apply-templates select="#* | node()"/>
</xsl:template>
<xsl:template match="text() | comment() | processing-instruction()">
<xsl:copy>
<xsl:apply-templates select="text() | comment() | processing-instruction()"/>
</xsl:copy>
</xsl:template>
<!-- Template used to copy elements -->
<xsl:template match="*">
<xsl:variable name="name">
<xsl:choose>
<xsl:when test="contains(name(), ':')">
<xsl:value-of select="name()"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="local-name()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:element name="{$name}" namespace="{$new_namespace}">
<!-- Copy all namespace through except for namespace to be changed -->
<xsl:for-each select="namespace::*">
<xsl:if test="string(.)!=$old_namespace">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:for-each>
<xsl:apply-templates select="node()|#*"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Note: My first answer was wrong because in XSLT 1.0, you can't use variable references within a match pattern.
This style-sheet will take either Sample1 or Sample2 as input document and replace all occurrences of the old namespace, from the element names, with the new namespace. Note: you can change the xsl:variable for xsl:param.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:variable name="old_namespace" select="'http://testlibrary'" />
<xsl:variable name="new_namespace" select="'http://newlibrary'" />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:choose>
<xsl:when test="namespace-uri()=$old_namespace">
<xsl:element name="{local-name()}" namespace="{$new_namespace}">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Caveat
The above style-sheet will only change the namespace of the elements. It will not change the namespaces of attributes, nor will it remove extraneous namespaces nodes.
On a more specific solution
It is very unusual to require a general solution for an operation on a variable namespace. Namespaces, being what they are tend to be fixed and known. Consider carefully, if you really need a generalized solution. If you need a specific solution, meaning replacing occurrences of a specific namespace, then things get a lot easier, such as with this style-sheet...
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:old="http://testlibrary"
xmlns:new="http://newlibrary">
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="old:*">
<xsl:element name="{local-name()}" namespace="http://newlibrary">
<xsl:apply-templates select="#*|node()" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
UPDATE
I just noticed Dimitre's solution to a very similar question here.
How can i replace an attribute in xml using xsl transformation, depending on its value.
For example, if there is such xml
<Text Style='style1'>
...
</Text>
transform it to
<Text Font='Arial' Bold='true' Color='Red'>
...
</Text>
For Style='style2' set another attributes and values, for example Font='Sans' Italic='true'.
One posible way: ussing attribute sets. This stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:attribute-set name="style1">
<xsl:attribute name="Font">Arial</xsl:attribute>
<xsl:attribute name="Bold">true</xsl:attribute>
<xsl:attribute name="Color">Red</xsl:attribute>
</xsl:attribute-set>
<xsl:attribute-set name="style2">
<xsl:attribute name="Font">Sans</xsl:attribute>
<xsl:attribute name="Italic">true</xsl:attribute>
</xsl:attribute-set>
<xsl:template match="Text[#Style='style1']">
<xsl:copy use-attribute-sets="style1">
<xsl:copy-of select="#*[name()!='Style']"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="Text[#Style='style2']">
<xsl:copy use-attribute-sets="style2">
<xsl:copy-of select="#*[name()!='Style']"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
With this input:
<root>
<Text Style='style1'></Text>
<Text Style='style2'></Text>
</root>
Output:
<Text Font="Arial" Bold="true" Color="Red"></Text>
<Text Font="Sans" Italic="true"></Text>
Other way: inline "attribute sets". This stylesheet:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="my"
exclude-result-prefixes="my">
<xsl:output indent="yes"/>
<my:style1 Font="Arial" Bold="true" Color="Red"/>
<my:style2 Font="Sans" Italic="true"/>
<xsl:template match="Text[#Style]">
<xsl:copy>
<xsl:copy-of select="document('')/*/my:*
[local-name()=current()/#Style]/#*"/>
<xsl:copy-of select="#*[name()!='Style']"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
You will need to have some kind of rule that you use to convert the style from one to the other. Making the assumption you are inputting html you will need something like.
<xsl:template match="#* | node()">
<xsl:choose>
<xsl:when test="local-name() = 'Style'">
<xsl:apply-templates select="." mode="Style" />
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="#Style" mode="Style">
<xsl:choose>
<xsl:when test="node() = 'style1'">
<xsl:attribute name="Font">Arial</xsl:attribute>
<xsl:attribute name="Bold">true</xsl:attribute>
<xsl:attribute name="Color">Red</xsl:attribute>
</xsl:when>
<xsl:when test="node() = 'style2'">
<xsl:attribute name="Font">Sans</xsl:attribute>
<xsl:attribute name="Bold">true</xsl:attribute>
</xsl:when>
</xsl:choose>
</xsl:template>
I have an XSLT file generating plain HTML. I need to wrap some elements in CDATA blocks, so intend to use cdata-section-elements. But, if the element I want to have contain CDATA is only one <p> on the page, how do I get it to not put CDATA in all the other <p> elements?
The input data is this:
<item>
...
<g:category>Gifts under £10</g:category>
</item>
My XSL is:
<xsl:element name="a">
<xsl:attribute name="href">productlist.aspx</xsl:attribute>
<xsl:copy-of select="text()" />
</xsl:element>
I want this to render something like:
Gifts under £10
But all I get is:
Gifts under £10
Well assuming you have some way of targeting the <p> tag that you want to enclose in CDATA section, you could do something like:
<xsl:output method="xml" version="1.0" encoding="UTF-8"
indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="p[#test = 'test']">
<xsl:copy>
<xsl:text disable-output-escaping="yes"><![CDATA[</xsl:text>
<xsl:apply-templates/>
<xsl:text disable-output-escaping="yes">]]></xsl:text>
</xsl:copy>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
In this case all <p> tags with an attribute test = 'test' will have CDATA applied to them, all other tags will just be output as normal.
The code I have is:
<xsl:element name="a">
<xsl:attribute name="href">
product.aspx?prod=<xsl:copy-of select="title/text()" />
</xsl:attribute>
<xsl:text disable-output-escaping="yes"><![CDATA[</xsl:text>
<xsl:copy-of select="g:price" /> - <xsl:copy-of select="title/text()" />
<xsl:text disable-output-escaping="yes">]]></xsl:text>
</xsl:element>