I am using selenium with perl and have label on page, to access this label i have following xpath: //*[text()='some here'] , the problem that a need to get full xpath of this element, like /html/body/table/tr/..../any other/and other/ , is there is any selenium method or perl function ? looking for perl solution or any other working things.
thanks
looking for perl solution or any other
working things
This XPath 2.0 expression:
string-join(for $node in ancestor-or-self::node()
return concat(('#')[$node/self::attribute()],
$node/name(),
(concat('[',
count($node/preceding-sibling::node()
[name()=$node/name()]) + 1,
']'))[$node/../node()
[name()=$node/name()][2]]),
'/')
Edit: Shorter expression.
This XSLT 1.0 transformation produces an XPath expression for every node contained in the $pNode parameter:
<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="node()|#*">
<path>
<xsl:call-template name="buildPath"/>
</path>
<xsl:apply-templates select="node()|#*"/>
</xsl:template>
<xsl:template name="buildPath">
<xsl:variable name="pNode" select="."/>
<xsl:variable name="theResult">
<xsl:for-each select="$pNode">
<xsl:variable name="theNode" select="."/>
<xsl:for-each select=
"$theNode
|
$theNode/ancestor-or-self::node()[..]">
<xsl:element name="slash">/</xsl:element>
<xsl:choose>
<xsl:when test="self::*">
<xsl:element name="nodeName">
<xsl:value-of select="name()"/>
<xsl:variable name="thisPosition" select=
"count(preceding-sibling::*
[name(current())
=
name()])"/>
<xsl:variable name="numFollowing" select=
"count(following-sibling::
*[name(current())
=
name()])"/>
<xsl:if test="$thisPosition + $numFollowing > 0">
<xsl:value-of select=
"concat('[', $thisPosition +1, ']')"/>
</xsl:if>
</xsl:element>
</xsl:when>
<xsl:otherwise> <!-- This node is not an element -->
<xsl:choose>
<xsl:when test="count(. | ../#*) = count(../#*)">
<!-- Attribute -->
<xsl:element name="nodeName">
<xsl:value-of select="concat('#',name())"/>
</xsl:element>
</xsl:when>
<xsl:when test="self::text()"> <!-- Text -->
<xsl:element name="nodeName">
<xsl:value-of select="'text()'"/>
<xsl:variable name="thisPosition"
select="count(preceding-sibling::text())"/>
<xsl:variable name="numFollowing"
select="count(following-sibling::text())"/>
<xsl:if test="$thisPosition + $numFollowing > 0">
<xsl:value-of select=
"concat('[', $thisPosition +1, ']')"/>
</xsl:if>
</xsl:element>
</xsl:when>
<xsl:when test="self::processing-instruction()">
<!-- Processing Instruction -->
<xsl:element name="nodeName">
<xsl:value-of select="'processing-instruction()'"/>
<xsl:variable name="thisPosition"
select="count(preceding-sibling::processing-instruction())"/>
<xsl:variable name="numFollowing"
select="count(following-sibling::processing-instruction())"/>
<xsl:if test="$thisPosition + $numFollowing > 0">
<xsl:value-of select=
"concat('[', $thisPosition +1, ']')"/>
</xsl:if>
</xsl:element>
</xsl:when>
<xsl:when test="self::comment()"> <!-- Comment -->
<xsl:element name="nodeName">
<xsl:value-of select="'comment()'"/>
<xsl:variable name="thisPosition"
select="count(preceding-sibling::comment())"/>
<xsl:variable name="numFollowing"
select="count(following-sibling::comment())"/>
<xsl:if test="$thisPosition + $numFollowing > 0">
<xsl:value-of select=
"concat('[', $thisPosition +1, ']')"/>
</xsl:if>
</xsl:element>
</xsl:when>
<!-- Namespace: -->
<xsl:when test=
"count(. | ../namespace::*)
=
count(../namespace::*)">
<xsl:variable name="apos">'</xsl:variable>
<xsl:element name="nodeName">
<xsl:value-of select="concat('namespace::*',
'[local-name() = ', $apos, local-name(), $apos, ']')"/>
</xsl:element>
</xsl:when>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<!-- <xsl:text>
</xsl:text> -->
</xsl:for-each>
</xsl:variable>
<xsl:value-of select="$theResult"/>
</xsl:template>
</xsl:stylesheet>
when applied on the following XML document:
<div id="entry-1" class="item-asset asset hentry">
<div class="asset-header">
<h2 class="asset-name entry-title">
<a rel="bookmark" href="http://blahblah.com/paper-scissors">Paper Scissors</a>
</h2>
</div>
<div class="asset-content entry-content">
<div class="asset-body">
<p>Paper and scissors</p>
</div>
</div>
</div>
the result is a list of the XPath expressions for every node in the document:
<path>/div</path>
<path>/div/#id</path>
<path>/div/#class</path>
<path>/div/div[1]</path>
<path>/div/div[1]/#class</path>
<path>/div/div[1]/h2</path>
<path>/div/div[1]/h2/#class</path>
<path>/div/div[1]/h2/a</path>
<path>/div/div[1]/h2/a/#rel</path>
<path>/div/div[1]/h2/a/#href</path>
<path>/div/div[1]/h2/a/text()</path>
<path>/div/div[2]</path>
<path>/div/div[2]/#class</path>
<path>/div/div[2]/div</path>
<path>/div/div[2]/div/#class</path>
<path>/div/div[2]/div/p</path>
<path>/div/div[2]/div/p/text()</path>
Related
Input XML
<PayrollGroup xmlns="http://www.example.org">
<Payroll>
<EmpID>1</EmpID>
<Name>Jacob</Name>
<WeekNumber>12</WeekNumber>
<HoursType>Regular</HoursType>
<Hours>80</Hours>
<EarningsType></EarningsType>
<Earnings></Earnings>
</Payroll>
<Payroll>
<EmpID>1</EmpID>
<Name>Jacob</Name>
<WeekNumber>12</WeekNumber>
<HoursType></HoursType>
<Hours></Hours>
<EarningsType>Regular</EarningsType>
<Earnings>800.00</Earnings>
</Payroll>
<Payroll>
<EmpID>2</EmpID>
<Name>John</Name>
<WeekNumber>12</WeekNumber>
<HoursType></HoursType>
<Hours></Hours>
<EarningsType>Regular</EarningsType>
<Earnings>1000.00</Earnings>
</Payroll>
<Payroll>
<EmpID>3</EmpID>
<Name>Augira</Name>
<WeekNumber>12</WeekNumber>
<HoursType>Other</HoursType>
<Hours>12</Hours>
<EarningsType></EarningsType>
<Earnings></Earnings>
</Payroll>
<Payroll>
<EmpID>4</EmpID>
<Name>Satya</Name>
<WeekNumber>12</WeekNumber>
<HoursType>SMT</HoursType>
<Hours>40</Hours>
<EarningsType></EarningsType>
<Earnings></Earnings>
</Payroll>
<Payroll>
<EmpID>4</EmpID>
<Name>Satya</Name>
<WeekNumber>12</WeekNumber>
<HoursType></HoursType>
<Hours></Hours>
<EarningsType>SMT</EarningsType>
<Earnings>600.00</Earnings>
</Payroll>
</PayrollGroup>
Output XML
<PayrollGroup xmlns="http://www.example.org">
<Payroll>
<EmpID>1</EmpID>
<Name>Jacob</Name>
<WeekNumber>12</WeekNumber>
<HoursType>Regular</HoursType>
<Hours>80</Hours>
<EarningsType>Regular</EarningsType>
<Earnings>800.00</Earnings>
</Payroll>
<Payroll>
<EmpID>2</EmpID>
<Name>John</Name>
<WeekNumber>12</WeekNumber>
<HoursType></HoursType>
<Hours></Hours>
<EarningsType>Regular</EarningsType>
<Earnings>1000.00</Earnings>
</Payroll>
<Payroll>
<EmpID>3</EmpID>
<Name>Augira</Name>
<WeekNumber>12</WeekNumber>
<HoursType>Other</HoursType>
<Hours>12</Hours>
<EarningsType></EarningsType>
<Earnings></Earnings>
</Payroll>
<Payroll>
<EmpID>4</EmpID>
<Name>Satya</Name>
<WeekNumber>12</WeekNumber>
<HoursType>SMT</HoursType>
<Hours>40</Hours>
<EarningsType>SMT</EarningsType>
<Earnings>600.00</Earnings>
</Payroll>
</PayrollGroup>
Problem Statement :
Need an XSLT to transform from Input XML above to Output XML
The actual sample of input XML is around 10 MB and I wrote a transformation that does looping on PayrollGroup twice which is of O(n2) order of n square. This is extremely getting bad for my server and is throwing out of memory exception.
Can someone provide a better performant XSLT.?
Edit:
The below are 2 XSLT's that I am using to achieve this one after the other
<xsl:template match="/">
<ns0:PayrollGroup>
<xsl:for-each select="/ns0:PayrollGroup/ns0:Payroll">
<xsl:variable name="empId" select="ns0:EmpID"/>
<xsl:variable name="earningsType" select="ns0:EarningsType"/>
<xsl:variable name="hoursType" select="ns0:HoursType"/>
<ns0:Payroll>
<ns0:EmpID>
<xsl:value-of select="ns0:EmpID"/>
</ns0:EmpID>
<ns0:Name>
<xsl:value-of select="ns0:Name"/>
</ns0:Name>
<ns0:WeekNumber>
<xsl:value-of select="ns0:WeekNumber"/>
</ns0:WeekNumber>
<xsl:choose>
<xsl:when test="ns0:HoursType = '' and ns0:Hours ='' and ns0:EarningsType !='' and ns0:Earnings !='' ">
<ns0:HoursType>
<xsl:value-of select="/ns0:PayrollGroup/ns0:Payroll[ns0:EmpID = $empId and ns0:HoursType = $earningsType]/ns0:HoursType"/>
</ns0:HoursType>
<ns0:Hours>
<xsl:value-of select="/ns0:PayrollGroup/ns0:Payroll[ns0:EmpID = $empId and ns0:HoursType = $earningsType]/ns0:Hours"/>
</ns0:Hours>
<ns0:EarningsType>
<xsl:value-of select="ns0:EarningsType"/>
</ns0:EarningsType>
<ns0:Earnings>
<xsl:value-of select="ns0:Earnings"/>
</ns0:Earnings>
</xsl:when>
<xsl:when test="ns0:HoursType != '' and ns0:Hours !='' and ns0:EarningsType ='' and ns0:Earnings ='' ">
<ns0:HoursType>
<xsl:value-of select="ns0:HoursType"/>
</ns0:HoursType>
<ns0:Hours>
<xsl:value-of select="ns0:Hours"/>
</ns0:Hours>
<ns0:EarningsType>
<xsl:value-of select="/ns0:PayrollGroup/ns0:Payroll[ns0:EmpID = $empId and ns0:EarningsType = $hoursType]/ns0:EarningsType"/>
</ns0:EarningsType>
<ns0:Earnings>
<xsl:value-of select="/ns0:PayrollGroup/ns0:Payroll[ns0:EmpID = $empId and ns0:EarningsType = $hoursType]/ns0:Earnings"/>
</ns0:Earnings>
</xsl:when>
<xsl:otherwise>
<ns0:HoursType>
<xsl:value-of select="ns0:HoursType"/>
</ns0:HoursType>
<ns0:Hours>
<xsl:value-of select="ns0:Hours"/>
</ns0:Hours>
<ns0:EarningsType>
<xsl:value-of select="ns0:EarningsType"/>
</ns0:EarningsType>
<ns0:Earnings>
<xsl:value-of select="ns0:Earnings"/>
</ns0:Earnings>
</xsl:otherwise>
</xsl:choose>
</ns0:Payroll>
</xsl:for-each>
</ns0:PayrollGroup>
</xsl:template>
After that the below XSLT to remove duplicates
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ns0:PayrollGroup/ns0:Payroll">
<xsl:if test="not(following::ns0:PayrollGroup/ns0:Payroll[ns0:EmpID = current()/ns0:EmpID])">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:if>
</xsl:template>
It is not clear whether you are using one or two separate XSLT stylesheets here. However, you only need one, and the way to remove duplicates in XSLT 2.0 is use xsl:for-each-group. So, instead of doing this...
<xsl:for-each select="/ns0:PayrollGroup/ns0:Payroll">
Do this...
<xsl:for-each-group select="/ns0:PayrollGroup/ns0:Payroll" group-by="ns0:EmpID">
In addition to this, the following line (and similar ones) could affect performance:
<xsl:value-of select="/ns0:PayrollGroup/ns0:Payroll[ns0:EmpID = $empId and ns0:HoursType = $earningsType]/ns0:HoursType"/>
This is because they would have to search the entire XML document for a match. As you are using xsl:for-each-group you can restrict the search to only the current group (i.e. Payroll elements with the same EmpID)
<xsl:value-of select="current-group()[ns0:HoursType = $earningsType]/ns0:HoursType"/>
Try this XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns0="http://www.example.org"
version="2.0">
<xsl:key name="Emps" match="ns0:Payroll" use="ns0:EmpID" />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:output method="xml" indent="yes" />
<xsl:template match="/">
<ns0:PayrollGroup>
<xsl:for-each-group select="/ns0:PayrollGroup/ns0:Payroll" group-by="ns0:EmpID">
<xsl:variable name="empId" select="ns0:EmpID"/>
<xsl:variable name="earningsType" select="ns0:EarningsType"/>
<xsl:variable name="hoursType" select="ns0:HoursType"/>
<ns0:Payroll>
<ns0:EmpID>
<xsl:value-of select="ns0:EmpID"/>
</ns0:EmpID>
<ns0:Name>
<xsl:value-of select="ns0:Name"/>
</ns0:Name>
<ns0:WeekNumber>
<xsl:value-of select="ns0:WeekNumber"/>
</ns0:WeekNumber>
<xsl:choose>
<xsl:when test="ns0:HoursType = '' and ns0:Hours ='' and ns0:EarningsType !='' and ns0:Earnings !='' ">
<ns0:HoursType>
<xsl:value-of select="current-group()[ns0:HoursType = $earningsType]/ns0:HoursType"/>
</ns0:HoursType>
<ns0:Hours>
<xsl:value-of select="current-group()[ns0:HoursType = $earningsType]/ns0:Hours"/>
</ns0:Hours>
<ns0:EarningsType>
<xsl:value-of select="ns0:EarningsType"/>
</ns0:EarningsType>
<ns0:Earnings>
<xsl:value-of select="ns0:Earnings"/>
</ns0:Earnings>
</xsl:when>
<xsl:when test="ns0:HoursType != '' and ns0:Hours !='' and ns0:EarningsType ='' and ns0:Earnings ='' ">
<ns0:HoursType>
<xsl:value-of select="ns0:HoursType"/>
</ns0:HoursType>
<ns0:Hours>
<xsl:value-of select="ns0:Hours"/>
</ns0:Hours>
<ns0:EarningsType>
<xsl:value-of select="current-group()[ns0:EarningsType = $hoursType]/ns0:EarningsType"/>
</ns0:EarningsType>
<ns0:Earnings>
<xsl:value-of select="current-group()[ns0:EarningsType = $hoursType]/ns0:Earnings"/>
</ns0:Earnings>
</xsl:when>
<xsl:otherwise>
<ns0:HoursType>
<xsl:value-of select="ns0:HoursType"/>
</ns0:HoursType>
<ns0:Hours>
<xsl:value-of select="ns0:Hours"/>
</ns0:Hours>
<ns0:EarningsType>
<xsl:value-of select="ns0:EarningsType"/>
</ns0:EarningsType>
<ns0:Earnings>
<xsl:value-of select="ns0:Earnings"/>
</ns0:Earnings>
</xsl:otherwise>
</xsl:choose>
</ns0:Payroll>
</xsl:for-each-group>
</ns0:PayrollGroup>
</xsl:template>
</xsl:stylesheet>
I want to extract short lemmas out of text for some explanatory notes. That is, if the text is too long it should output only the first and the last word. This works:
<?xml version="1.0" encoding="UTF-8"?>
<lemma>
<a><b>I</b> can what I can and <b><c>what</c></b> I can't I can</a>
</lemma>
when this xslt is applied
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
version="2.0">
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
<!-- Identity template : copy all text nodes, elements and attributes -->
<xsl:template match="#*|node()">
<xsl:copy copy-namespaces="no">
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="lemma">
<xsl:value-of select="."/>
<xsl:choose>
<xsl:when test="string-length(normalize-space(a)) > 20">
<xsl:value-of select="tokenize(a,' ')[1]"/>
<xsl:text> […] </xsl:text>
<xsl:value-of select="tokenize(a,' ')[last()]"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="a"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
produces the desired output:
I can what I can and what I can't I can
I […] can
Unfortunately whenever two child elements are immediately adjacent the space in between is coded as child-node named „space“. The above solution doesn't work with:
<lemma>
<a><b>I</b><space/><b>can</b> what I can and what I can't I can</a>
</lemma>
I tried to have the single space-special character processed before, but that doesn't work (and I know why), I just don't know how to do it better. It would work with two XLST-runs, I suppose.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
version="2.0">
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
<!-- Identity template : copy all text nodes, elements and attributes -->
<xsl:template match="#*|node()">
<xsl:copy copy-namespaces="no">
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="space">
</xsl:template>
<xsl:template match="lemma">
<xsl:apply-templates select="space"/>
<xsl:value-of select="."/>
<xsl:choose>
<xsl:when test="string-length(normalize-space(a)) > 20">
<xsl:value-of select="tokenize(a,' ')[1]"/>
<xsl:text> […] </xsl:text>
<xsl:value-of select="tokenize(a,' ')[last()]"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="a"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Output:
Ican what I can and what I can't I can
Ican […] can
You could do an xsl:apply-templates to process a and save it in a variable...
XML Input
<doc>
<lemma>
<a><b>I</b> can what I can and <b><c>what</c></b> I can't I can</a>
</lemma>
<lemma>
<a><b>I</b><space/><b>can</b> what I can and what I can't I can</a>
</lemma>
</doc>
XSLT 2.0
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="space">
<xsl:text> </xsl:text>
</xsl:template>
<xsl:template match="lemma">
<xsl:variable name="a">
<xsl:apply-templates select="a"/>
</xsl:variable>
<xsl:variable name="norm" select="normalize-space($a)"/>
<xsl:variable name="tokens" select="tokenize($norm,'\s')"/>
<xsl:copy>
<result>
<xsl:value-of select="$norm"/>
</result>
<result>
<xsl:value-of select="
if (string-length($norm) > 20) then
concat($tokens[1],' […] ', $tokens[last()])
else $norm"/>
</result>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
XML Output
<doc>
<lemma>
<result>I can what I can and what I can't I can</result>
<result>I […] can</result>
</lemma>
<lemma>
<result>I can what I can and what I can't I can</result>
<result>I […] can</result>
</lemma>
</doc>
i need to add an attribute initial-page-number to a tag fo:sequence
tha tag is
<fo:page-sequence master-reference="alternating" initial-page-number="1"><fo:page-sequence>
..
...
</fo:page-sequence>
become
<fo:page-sequence master-reference="alternating" initial-page-number="1">
..
</fo:page-sequence>
but with the xslt i obtain two fo:page:
<fo:page-sequence master-reference="alternating" initial-page-number="1"><fo:page-sequence>
</fo:page-sequence></fo:page-sequence>
How can i replace old fo:page-sequence with new one?
This is my xsl stylesheet:
<xsl:stylesheet>
<xsl:template match="ss:split/fo:page-sequence">
<xsl:choose>
<xsl:when test="#master-reference['alternating']">
<xsl:element name="fo:page-sequence">
<xsl:for-each select="#*">
<xsl:attribute name="{name()}"><xsl:value-of select="."/></xsl:attribute>
</xsl:for-each>
<xsl:attribute name="initial-page-number">
<xsl:value-of select="1"/>
</xsl:attribute>
<xsl:copy>
<xsl:apply-templates select="child::*"/>
</xsl:copy>
</xsl:element>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template match='comment()'>
<xsl:comment><xsl:value-of select="."/></xsl:comment>
</xsl:template>
<xsl:template match="#*|*">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Your stylesheet changes every fo:page-sequence because the predicate ['alternating'] is always true.
You can check for the master-reference value in the match pattern, plus you can just copy the existing attributes, and you can copy the contents of the fo:page-sequence since it won't contain another fo:page-sequence:
<xsl:template
match="ss:split/fo:page-sequence[#master-reference = 'alternating']">
<xsl:copy>
<xsl:copy-of select="#*" />
<xsl:attribute name="initial-page-number">1</xsl:attribute>
<xsl:copy-of select="node()" />
</xsl:copy>
</xsl:template>
Your stylesheet creates an fo:page-sequence using <xsl:element name="fo:page-sequence">, and another one with <xsl:copy> (as the matching element is an fo:page-sequence).
Just remove the xsl:copy (but leave <xsl:apply-templates select="child::*"/>, as you want to process the children of the current node!) and you should get what you need.
I've the below XML line of code.
<title><page>651</page>CHAPTER 13 This is <content-style font-style="italic">This goes in content-style</content-style> The title</title>
Here i'm trying to do the below.
Get the number after CHAPTER and concat it with Chapter, i'm able to do it with the below code.
<xsl:value-of select="concat('Chapter ', substring-before(substring-after(child::title,' '),' ')"/>
ignore the page in the title, and i use the below template match and able to do it.
<xsl:template match="title/page"/>
If there is just plain data, i'm using the below to get it.
<xsl:value of select ="substring-after(substring-after(./title,' '),' ')">
But the problem came in the above type, here i need to apply templates on substring-after(substring-after(.,' '),' ') and unfortunately this is not working.
I have the below XSLT
<xsl:template match ="title">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="content-style">
<xsl:variable name="fontStyle">
<xsl:value-of select="concat('font-style-',#font-style)"/>
</xsl:variable>
<span class="{$fontStyle}">
<xsl:value-of select="."/>
<xsl:apply-templates select="para"/>
</span>
</xsl:template>
expected O/P
<div class="chapter-title">
<span class="chapter-num">Chapter 13</span><br /><br /> This is <span class="font-style-italic">This goes in content-style</span> the title</span></div>
Can you please let me know how can i do this.
Thanks
Your expected output has an unmatched span end tag.
Ignoring that, I would do something like:
<xsl:template match ="title">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="content-style">
<span class="font-style-{#font-style}">
<xsl:value-of select="."/>
</span>
</xsl:template>
<xsl:template match="title/text()">
<xsl:analyze-string select="." regex="Chapter [0-9]+">
<xsl:matching-substring>
<span class="chapter-num">
<xsl:value-of select="."/>
</span><br/>>br/>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:-nonmatching-substring>
</xsl:analyze-string>
</xsl:template>
I have this function which tries to replace dots and/or - with _
I'm limited to use xpath 1 so replace function is NOT an option. The template works not to much fine because if I use something like this:
FOO-BAR.THING-MADRID.html
it gives me out on screen this thing:
FOO-BAR.THING-MADRID.html
the middle dot is not replaced.
Someone could help me?
<xsl:template name="replaceDots">
<xsl:param name="outputString"/>
<xsl:variable name="target">.</xsl:variable>
<xsl:variable name="source">-</xsl:variable>
<xsl:variable name="replacement">_</xsl:variable>
<xsl:choose>
<xsl:when test="contains($outputString,$source)">
<xsl:value-of select="concat(substring-before($outputString,$source),$replacement)" disable-output-escaping="yes"/>
<xsl:call-template name="replaceDots">
<xsl:with-param name="outputString" select="substring-after($outputString,$source)"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="contains($outputString,$target)">
<xsl:value-of select="concat(substring-before($outputString,$target),$replacement)" disable-output-escaping="yes"/>
<xsl:call-template name="replaceDots">
<xsl:with-param name="outputString" select="substring-after($outputString,$target)"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$outputString" disable-output-escaping="yes"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
To replace all dots or dashes with underscores, you do not need an <xsl:template>. You can use:
<xsl:value-of select="translate(., '-.', '__')" />
If you want to keep the ".html", you can extend this like so:
<xsl:value-of select="
concat(
translate(substring-before(., '.html'), '-.', '__'),
'.hmtl'
)
" />
For a generic "string replace" template in XSLT, look at this question, for example.