<div>
<a href="M_TestNamespace_StoredNumber_Swap``1_2_890a5ef1.htm">
Swap
<span class="languageSpecificText">
<span class="cs"><</span>
<span class="vb">(Of </span><span class="cpp"><</span>
<span class="fs"><'</span><span class="nu">(</span>
</span>
T
<span class="languageSpecificText">
<span class="cs">></span>
<span class="vb">)</span>
<span class="cpp">></span>
<span class="fs">></span>
<span class="nu">)</span>
</span>
</a>
<div>
I would like using XSLT and translate above into the result like this:
<div>
Swap(T)
<div>
FYI, the "(" and ")" are from <span class="nu"/>.
You might want to create a parameter to hold the 'nu' value.
<xsl:param name="lang" select="'nu'" />
Then, you would be able to extract the language specific text like so
<xsl:template match="span[#class='languageSpecificText']">
<xsl:value-of select="span[#class=$lang]" />
</xsl:template>
Here is the full XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:param name="lang" select="'nu'" />
<xsl:template match="a">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="span[#class='languageSpecificText']">
<xsl:value-of select="span[#class=$lang]" />
</xsl:template>
<xsl:template match="a/text()">
<xsl:value-of select="normalize-space()" />
</xsl:template>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
When applied to your sample XML, the following is output
<div>Swap(T)</div>
Change the parameter to 'vb' and you get the following
<div>Swap(Of T)</div>
Try like so:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="div">
<xsl:element name="div">
<xsl:value-of select="normalize-space(a/text()[1])"/>
<xsl:value-of select="(.//span/span[#class='nu'])[1]/text()"/>
<xsl:value-of select="normalize-space(a/text()[2])"/>
<xsl:value-of select="(.//span/span[#class='nu'])[2]/text()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
I've assumed that the <div> is correctly closed :).
One of the shortest ways to generate the wanted result is:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="a">
<div><xsl:apply-templates/></div>
</xsl:template>
<xsl:template match="a/text() | span[#class='nu']/text()">
<xsl:value-of select="normalize-space()"/>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
Explanation:
All text nodes are ignored by: <xsl:template match="text()"/> -- this effectively "deletes" them from the output.
Only the text-node children of a and span[#class='nu'] are treated differently (used to generate text-nodes in the output -- by the template matching: a/text() | span[#class='nu']/text().
The unwanted white-space in the text-node children of a is removed using the standard XPath function normalize-space()
Related
If someone would be kind enough to tell me why the following <xsl:call-template name="Log"> won't work?
XML File:
<?xml version="1.0" encoding="UTF-8"?>
<TextMessages>
<Message>[Step]</Message>
<Message>Step ID: 1</Message>
<Message>Description</Message>
</TextMessages>
XSLT File:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<html>
<body>
<h2>My CD Collection ></h2>
<p>
<xsl:call-template name="Log">
</xsl:call-template>
</p>
</body>
</html>
</xsl:template>
<xsl:template name ="Log">
<xsl:variable name="break"><br/></xsl:variable>
<xsl:for-each select="TextMessages">
<p>
<xsl:value-of select="."/>
<xsl:value-of select="$break"/>
</p>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
The wanted output:
My CD Collection >
[Step]<br/>
Step ID: 1<br/>
Description<br/>
The real problem has also parameters which I call with parameters, but not sure if that is the problem.
<p>
<xsl:call-template name="Log">
<xsl:with-param name="testId" select="#testId" />
</xsl:call-template>
</p>
<xsl:template name ="Log">
<xsl:param name="testId" />
<xsl:variable name="break"><br/></xsl:variable>
<xsl:for-each select="/t:TestRun/t:Results/t:UnitTestResult[#testId=$testId]/t:Output/t:TextMessages/t:Message">
<p>
<xsl:value-of select="."/>
<xsl:value-of select="$break"/>
</p>
</xsl:for-each>
</xsl:template>
If i am guessing correctly, you want to change:
<xsl:template name ="Log">
<xsl:variable name="break"><br/></xsl:variable>
<xsl:for-each select="TextMessages">
<p>
<xsl:value-of select="."/>
<xsl:value-of select="$break"/>
</p>
</xsl:for-each>
</xsl:template>
to:
<xsl:template name="Log">
<xsl:for-each select="TextMessages/Message">
<p>
<xsl:value-of select="."/>
</p>
<hr/>
</xsl:for-each>
</xsl:template>
Note:
You should never have to use a hack like <br/> to output HTML or XML valid markup;
I am not sure why you need to call a named template here, instead of simply including the xsl:for-each in the first template, or just applying templates to the Message elements.
Adding the line
<xsl:output method="text" version="1.0" encoding="UTF-8" />
to your XSLT file directly after the <xsl:stylesheet... > line will you the (partly desired) result of
My CD Collection >
[Step]
Step ID: 1
Description
With "partly" I do refer to the first line - which you explicitly want to be output by including <h2>My CD Collection ></h2> in your XSLT - but not mention in your output text.
I have an xml coming as below
<Envelope>
<content>
<feild1>1</feild1>
....
<feild10>10<feild10>
</content>
</Envelope>
but want the xml to be (add the namespace prefix as xs1 and content lower case c to Upper case "C"
<Envelope>
<Content> <!-- Note the lower case c chnaged to Upper Case --->
<xs1:feild1>1</xs1:feild1> <!-- and for the feild, xs1 is added as prefix -->
....
<xs1:feild10>10</xs1:feild10>
</Content>
</Envelope>
Please help looking for XSLT 1.0
Here is my XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs1="https://temp">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="*">
<xsl:element name="{name()}" namespace="https://temp">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="#*">
<xsl:attribute name="{name}"><xsl:value-of select="."/></xsl:attribute>
</xsl:template>
</xsl:stylesheet>
Hope this helps
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs1="https://temp">
<xsl:template match="/">
<xsl:variable name="smallcase" select="'abcdefghijklmnopqrstuvwxyz'" />
<xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
<Envelope>
<xsl:for-each select="Envelope/*">
<xsl:variable name="root" select="local-name(.)"/>
<xsl:variable name="temp" select="translate($root,$smallcase,$uppercase)"/>
<xsl:variable name="temp2" select="concat(substring($temp,1,1),translate(substring($temp,2,string-length($temp)),$uppercase,$smallcase))"/>
<xsl:element name="{$temp2}">
<xsl:for-each select="child::*">
<xsl:element name="xs1:{local-name(.)}" namespace="https://temp">
<xsl:value-of select="node()"/>
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:for-each>
</Envelope>
</xsl:template>
</xsl:stylesheet>
I have the following XML: <a>Text with <b>stuff</b> here</a>
With my code:
<xsl:template match="*[local-name() = 'a'][namespace-uri()=namespace-uri(.)]">
<xsl:value-of select="normalize-space(text()) "/><xsl:text> </xsl:text>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="*[local-name() = 'b'][namespace-uri()=namespace-uri(.)]">
<xsl:value-of select="normalize-space(text())"/><xsl:text> </xsl:text>
<xsl:apply-templates/>
</xsl:template>
I only get the result:
Text with stuff
What I want is:
Text with stuff here.
So how do I handle the remaining text after the <b/> element?
Why is this so complicated? If this is really your XML input:
<a>Text with <b>stuff</b> here</a>
then the following stylesheet:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:template match="/">
<xsl:value-of select="a" />
</xsl:template>
</xsl:stylesheet>
will return the requested* result:
Text with stuff here
--
(*) except for the period at the end, which is not present in the input.
I need get some part of a tag. My XML is like that
<div class="item">
<h2>Vyzivovy poradca</h2>
...
...
<div class="watch"><span>sometihink</span></div>
</div>
And I need href attribute and "data-id" attribute. My template look like
<xsl:variable name="url" select="xhtml:h2/xhtml:a/href"/>
<xsl:variable name="job_id" select="xhtml:div[#class = 'watch']/xhtml:a/data-id"/>
<job>
<xsl:attribute name="id"><xsl:value-of select="$job_id"/></xsl:attribute>
<url name="url"><xsl:value-of select="$url"/></url>
</job>
and template for tag a is:
<xsl:template match="xhtml:a">
<xsl:copy>
<!-- can not copy href, cause it is not absolute url ! -->
<xsl:copy-of select="#align|#title|#rel|#itemprop|#itemtype|#itemscope"/>
<xsl:attribute name="target">_blank</xsl:attribute>
<xsl:apply-templates select="*|text()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()"><xsl:value-of select="normalize-space(.)"/></xsl:template>
<xsl:template match="text()[ancestor::xhtml:pre]"><xsl:value-of select="etl:regex-replace(., '(\s|\n)+', '$1', 'g')"/></xsl:template>
but it doesn't work, some ideas?
This input XML:
<div class="item">
<h2>
Vyzivovy poradca
</h2>
...
...
<div class="watch">
<a href="sth"
data-id="292931"
data-active="somethink"
data-inactive="blablalba"
data-class="monitored"
class="watchItem"
title="watching"><span>sometihink</span></a>
</div>
</div>
Given to this XSLT:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="//a[descendant::text() = 'sometihink']">
<root>
<href>
<xsl:value-of select="#href"/>
</href>
<data-id>
<xsl:value-of select="#data-id"/>
</data-id>
</root>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
Produces this output XML:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<href>sth</href>
<data-id>292931</data-id>
</root>
Notes:
I'm assuming that the "sometihink" content is the most unique
characteristic of the a you seek. If it's something else (such as the parent div[#class="watch"]), let me know and we can adjust.
Update per OP's comment below:
This updated XSLT:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<root>
<item-href>
<xsl:value-of select="//div[#class='item']/h2/a/#href"/>
</item-href>
<watch-data-id>
<xsl:value-of select="//div[#class='watch']/a/#data-id"/>
</watch-data-id>
</root>
</xsl:template>
</xsl:stylesheet>
Given the above input XML will yield this output XML:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<item-href>url.html</item-href>
<watch-data-id>292931</watch-data-id>
</root>
containing the requested attribute values.
I have the following XML document which needs to be parsed with an XSLT to HTML.
<root>
<c>
<c1>
<id>1</id>
<text>US</text>
</c1>
<c1>
<id>2</id>
<text>UK</text>
</c1>
</c>
</root>
The XSLT for converting this to HTML is given below.
<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="yes" />
<xsl:template match="root">
<html>
<xsl:for-each select="c/c1">
**<xsl:variable name="vTemplate" select="text"/>
<xsl:apply-templates select="$vTemplate[#name='text'"/>**
</xsl:for-each>
</html>
</xsl:template>
<xsl:template match="xsl:template[#name='text']" name="text">
<select>
<xsl:attribute name="id">
<xsl:value-of select="id"/>
</xsl:attribute>
</select>
</xsl:template>
</xsl:stylesheet>
I need to call a template depends up on the text field. So for the value US, one template will be executed and for UK, another will executed.
How to achieve this with a variable as a template name while calling the template? I just made a try but it gives error. Can someone help me to figure out where i made wrong?
I think it is not possible to choose name of template to be called dynamically. What could be done is xsl:choose utilization (perhaps with combination with mode attribute), like this
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/root">
<html>
<xsl:for-each select="c/c1">
<xsl:choose>
<xsl:when test="text = 'US'">
<xsl:apply-templates select="text" mode="US"/>
</xsl:when>
<xsl:when test="text = 'UK'">
<xsl:apply-templates select="text" mode="UK"/>
</xsl:when>
<xsl:otherwise>
<xsl:comment>Something's wrong</xsl:comment>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</html>
</xsl:template>
<xsl:template match="text" mode="US">
<xsl:comment>US mode</xsl:comment>
<select>
<xsl:attribute name="id">
<xsl:value-of select="preceding-sibling::id"/>
</xsl:attribute>
</select>
</xsl:template>
<xsl:template match="text" mode="UK">
<xsl:comment>UK mode</xsl:comment>
<select>
<xsl:attribute name="id">
<xsl:value-of select="preceding-sibling::id"/>
</xsl:attribute>
</select>
</xsl:template>
</xsl:stylesheet>
Or you can use match with appropriate predicate and avoid for-each like this
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/root">
<html>
<xsl:apply-templates select="//c1" />
</html>
</xsl:template>
<xsl:template match="c1[text = 'US']">
<xsl:comment>US mode</xsl:comment>
<select id="{id}" />
</xsl:template>
<xsl:template match="c1[text = 'UK']">
<xsl:comment>UK mode</xsl:comment>
<select id="{id}" />
</xsl:template>
</xsl:stylesheet>
The id attribute of select can be also filled by "Attribute value templates" (xpath in curly brackets) as shown in previous sample.