I have the following XML
<title>
This is a <highlight>test</highlight> thanks.
</title>
and want to convert into
<span class="title">this is a <span class="highlight">test</span> thanks.</span>
I try this xslt, only can ge the text inside title tag, how can I also convert the highlight tag?
<span class="title"><xsl:value-of select="title"/></span>
<xsl:template match="title">
<span class="title">
<xsl:apply-templates />
</span>
</xsl:template>
<xsl:template match="highlight">
<span class="highlight">
<xsl:apply-templates />
</span>
</xsl:template>
or, if you want, collapse it into a single template:
<xsl:template match="title|highlight">
<span class="{name()}">
<xsl:apply-templates />
</span>
</xsl:template>
Key point is the <xsl:apply-templates /> - it runs all child nodes of the current node through the appropriate templates. In the upper variant, the appropriate templates are separate, in the lower variant the one template is called recursively.
There is a default rule defined in XSLT that copies text nodes. All text is run through this rule by <apply-templates>, so text nodes appear in the output autmatically.
Use xsl:copy-of instead of xsl:value-of if you want a full copy of the node and all of its children:
<span class="title"><xsl:copy-of select="title"/></span>
But for what you are trying to do, I would create one template for the title element and one for the highlight element:
<xsl:template match="title">
<span class="title"><xsl:value-of select="." /></span>
<xsl:apply-templates />
</xsl:template>
<xsl:template match="highlight">
<span class="highlight"><xsl:value-of select="." /></span>
</xsl:template>
Related
I need to remove the child element on the bases of the value of an id attribute. If there is no value in id attribute or there is no id attribute at all in contentblock tag then just remove the element and parent element will remain same if present. Also if content block is direct child of root and that content block doesn't have value in id attribute or there is no id attribute then remove that element also.
Example:
<root>
<div>
<contentblock class="align-center" id="" />
</div>
<p>
<contentblock class="align-center" />
</p>
<h2>
<contentblock class="align-center" id="623a7a1f87dd1975ce084ac7"/>
</h2>
<contentblock class="align-center" id=""/>
<contentblock class="align-center" id="623a7a1f87dd1975ce084ac7"/>
<contentblock class="align-center"/>
</root>
Expected Result:
<root>
<div>
</div>
<p>
</p>
<h2>
<contentblock class="align-center" id="623a7a1f87dd1975ce084ac7"/>
</h2>
<contentblock class="align-center" id="623a7a1f87dd1975ce084ac7"/>
</root>
Thanks in advance for the help.
What i tried but didn't give the expected result:
<!--<xsl:template match="contentblock[not(parent::root)] | contentblock[(parent::root)]">-->
<!--<xsl:choose>-->
<!-- <xsl:if test="contentblock/#id[string-length(.) =0]">-->
<!-- <xsl:apply-templates/>-->
<!-- </xsl:if>-->
<!--</xsl:choose>-->
<!--</xsl:template>-->
Another try:
<xsl:template match="div[contentblock] | p[descendant::contentblock] | h2[descendant::contentblock] | h3[descendant::contentblock]">
<xsl:choose>
<xsl:when test="contentblock[#id!='']">
<xsl:apply-templates/>
</xsl:when>
</xsl:choose>
<xsl:choose>
<xsl:when test="contentblock[#id=''] | contentblock[not(#id)]">
<xsl:copy> <xsl:apply-templates select="#*"/></xsl:copy>
</xsl:when>
</xsl:choose>
</xsl:template>
I can't match <xsl:template match="contentblock[not(parent::root)]"> as it performs the transformation on content block element itself which gives me different result. And also above solution does not work when i get the xml like this. When contentblock have multiple level parents like here it's p and span are parents of contentblock.
<p id="5c3692c8af8fe1f061518abc">
<span bulb-font-face="museo-sans, sans-serif">
<contentblock class="align-center block-full-width" id="5c3686fdcb7de304cd51696f" />
</span>
</p>
This template would match contentblock elements with an id attribute that has some value:
<xsl:template match="contentblock[#id!='']"/>
You would have to apply this template to all relevant contentblock elements, and in the template you would have to return whatever you want to return, like
<xsl:copy-of select="."/>
I have an XSL 1.0 document with the following:
<div class="workgroup_title">
<xsl:value-of select="./#name"/>
</div>
I need to set the color for this element. The color is in the XML file
<abc.xyz.color>FF5733</abc.xyz.color>
To get it, I use this:
<xsl:value-of select="./abc.xyz.color"/>
What I would have liked to do is
<div class="workgroup_title" style="color:"#<xsl:value-of select="./abc.xyz.color"/>>
<xsl:value-of select="./#name"/>
</div>
That's not allowed, though.
Or:
<xsl:attribute style="color:">#<xsl:value-of select="./abc.xyz.color"/></xsl:attribute>
But color is not one of the attributes that can be set like that.
You can use attribute value templates to compute (parts of) the value of a literal result element: <div style="color: #{abc.xyz.color}">...</div>
The following templates should suffice your needs:
<xsl:template match="text()" /> <!-- Removes the text from the <abc.xyz.color>FF5733</abc.xyz.color> element -->
<xsl:template match="/*"> <!-- Copies the root element and its namespace -->
<xsl:copy>
<xsl:apply-templates select="node()|#*" />
</xsl:copy>
</xsl:template>
<xsl:template match="div[#class='workgroup_title']"> <!-- Applies the template to the <div> element -->
<xsl:copy>
<xsl:attribute name="style"><xsl:value-of select="concat('color: #',../abc.xyz.color,';')"/></xsl:attribute>
<xsl:copy-of select="node()|#*" />
</xsl:copy>
</xsl:template>
Its output is:
<root xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<div style="color: #FF5733;" class="workgroup_title">
<xsl:value-of select="./#name"/>
</div>
</root>
I have some data that i put in (image, title, text). I ahve 3 different elements in my xslt for each of them:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:udt="DotNetNuke/UserDefinedTable" exclude-result-prefixes="udt">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />
<!--
This prefix is used to generate module specific query strings
Each querystring or form value that starts with udt_{ModuleId}_param
will be added as parameter starting with param
-->
<xsl:variable name="prefix_param">udt_<xsl:value-of select="//udt:Context/udt:ModuleId" />_param</xsl:variable>
<xsl:template match="udt:Data" mode="list">
<xsl:value-of select="udt:Image" disable-output-escaping="yes" />
<xsl:value-of select="udt:Title" disable-output-escaping="yes" />
<xsl:value-of select="udt:Text" disable-output-escaping="yes" />
</xsl:template>
<xsl:template match="/udt:UserDefinedTable">
<xsl:variable name="currentData" select="udt:Data" />
<xsl:if test="$currentData">
<xsl:apply-templates select="$currentData" mode="list">
</xsl:apply-templates>
</xsl:if>
</xsl:template>
<xsl:template name="EditLink">
<xsl:if test="udt:EditLink">
<a href="{udt:EditLink}">
<img border="0" alt="edit" src="{//udt:Context/udt:ApplicationPath}/images/edit.gif" />
</a>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
I want to fill these elements each into its own div group, so my end result would be something like this:
<div id="images">
<!--all images here-->
</div>
<div id="title">
<!--all titles here-->
</div>
<div id="text">
<!--all texts here-->
</div>
Can this be achieved by any kind of grouping or whats the right aproach?
The concept to use xsl:value-of for your 3 element types is wrong,
as this instruction copies only the content of these elements,
without XML markup.
Assuming that the only goal is to reorder (group) your elements,
and they are direct descendants of the current element (udt:Data),
the task can be done the following way:
<xsl:template match="udt:Data">
<xsl:copy>
<div id="images">
<xsl:copy-of select="udt:Image"/>
</div>
<div id="title">
<xsl:copy-of select="udt:Title"/>
</div>
<div id="text">
<xsl:copy-of select="udt:Text"/>
</div>
</xsl:copy>
</xsl:template>
Of course, this is only a template, not the whole script.
Note that e.g. if these elements were located also at "deeper" descendant levels,
all the above XPath expressions should be prececed with descendant::.
And remember about including in your script all namespaces, the script refers to.
They should be declared in stylesheet tag.
I need to process attributes (of any node that has them) in a particular order. For example:
<test>
<event
era ="modern"
year ="1996"
quarter = "first"
day = "13"
month= "January"
bcad ="ad"
hour ="18"
minute = "23"
>The big game began.</event>
<happening
era ="modern"
day = "18"
bcad ="ad"
month= "February"
hour ="19"
minute = "24"
>The big game ended.</happening>
<other>Before time existed.</other>
</test>
This
<xsl:template match="test//*">
<div>
<xsl:apply-templates select="#*" />
<xsl:apply-templates />
</div>
</xsl:template>
<xsl:template match="#*">
<span class="{name()}">
<xsl:value-of select="."/>
</span>
</xsl:template>
would format things as I need them. That is, I'd get
<div><span class="era">modern</span>
<span class="year">1996</span>
<span class="quarter">first</span>
<span class="day">13</span>
<span class="month">January</span>
<span class="bcad">ad</span>
<span class="hour">18</span>
<span class="minute">23</span>The big game began.</div>
<div><span class="era">modern</span>
<span class="day">18</span>
<span class="bcad">ad</span>
<span class="month">February</span>
<span class="hour">19</span>
<span class="minute">24</span>The big game ended.</div>
<div>Before time existed.</div>
(though without the newlines I've added here for legibility).
But the order of the attributes wouldn't (necessarily) be right.
To fix that, I could change <xsl:apply-templates select="#*" /> to <xsl:call-template name="atts" /> and add a template that applies templates in the needed order, like this:
<xsl:template match="test//*">
<div>
<xsl:call-template name="atts" />
<xsl:apply-templates />
</div>
</xsl:template>
<xsl:template name="atts">
<xsl:apply-templates select="#era" />
<xsl:apply-templates select="#bcad" />
<xsl:apply-templates select="#year" />
<xsl:apply-templates select="#quarter" />
<xsl:apply-templates select="#month" />
<xsl:apply-templates select="#day" />
<xsl:apply-templates select="#hour" />
<xsl:apply-templates select="#minute" />
</xsl:template>
<xsl:template match="#*">
<span class="{name()}">
<xsl:value-of select="."/>
</span>
</xsl:template>
Is this the best-practices way to process attributes in a specified order? I keep wondering if there is a way that uses keys or a global variable.
I need to use XSLT 1.0 and in the real case, there are several dozen attributes, not just eight.
In contrast to elements for example, the order of attributes is not significant in XML, i.e. XPath and XSLT may process them in any order. Thus, the only way to force a given order, is to specify it somehow. One way is to call them explicitly as in your last code example. You can also extract all attribute names and store them in a separate XML file, e.g. something like
<attributes>
<attribute>era</attribute>
<attribute>year</attribute>
<attribute>month</attribute>
...
<attributes>
Now you can load these elements with the document() function and iterate over all attribute elements:
<xsl:variable name="attributes" select="document('attributes.xml')//attribute"/>
...
<xsl:template match="*">
<xsl:variable name="self" select="."/>
<xsl:for-each select="$attributes">
<xsl:apply-templates select="$self/#*[name()=current()]"/>
</xsl:for-each>
</xsl:template>
I have a item list and for each item I want to make it an url.
List:
<root>
<tags>
<tag>open source</tag>
<tag>open</tag>
<tag>advertisement</tag>
<tag>ad</tag>
</tags>
</root>
XSLT:
<xsl:template match="*">
<div class="tags">
<xsl:for-each select="/post/tags/tag">
<a href="#">
<xsl:value-of select="//tag"/>
</a>
</xsl:for-each>
</div>
</xsl:template>
Output:
<div class="tags">
open source
open source
open source
open source
</div>
What am I doing wrong?
A more XSLT way of doing the correct thing is add a "tag" template and modify your original:
<xsl:template match="*">
<div class="tags">
<xsl:apply-templates select="tag" />
</div>
</xsl:template>
<xsl:template match="tag">
<a href="#">
<xsl:value-of select="."/>
</a>
</xsl:template>
What you are doing with the value-of expression is selecting all of the tag nodes in the xml document:
<xsl:value-of select="//tag"/>
The effect of that is that only the first selected node will be used for the value.
You can use the following instead:
<xsl:value-of select="."/>
Where select="." will select the current node from the for-each.