I would like to group nodes which following-sibling
<doc>
<a>blabla</a>
<b>blabla</b>
<c>text C</c>
<d>text D</d>
<a>bla</a>
<d>text D</d>
<a>bla</a>
</doc>
output desired :
<doc>
<a>blabla</a>
<b>blabla</b>
<c>text C</c>
<GROUP>
<d>text D</d>
<a>bla</a>
<d>text D</d>
<a>bla</a>
</GROUP>
</doc>
I've tried :
<xsl:template match="doc">
<xsl:copy>
<xsl:for-each-group select="*"
group-adjacent="boolean(self::a | self::d)">
<xsl:choose>
<xsl:when test="current-grouping-key()">
<xsl:element name="GROUP">
<xsl:value-of select="current-group()"/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
How can i do to exclude a not preceding-sibling::*[1]=d ?
Thanks a lot.
I've found :
<xsl:template match="doc">
<xsl:copy>
<xsl:for-each-group select="*"
group-adjacent="self::a or self::d
[following-sibling::*[1][self::a or self::d]
or
(preceding-sibling::*[1][self::a or self::d])
]">
<xsl:choose>
<xsl:when test="current-grouping-key() and current-group()[2]">
<xsl:element name="GROUP">
<xsl:copy-of select="current-group()"/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
Please suggest to find replace the required text within one text() node, some times find-replace text repeated more than once.
Here, scripts should exclue the element '<p>'. Working fine when 'find' text occuring only once in a text node, if it occures more than once, then skipping the replace process (see first <p1>). Please suggest.
XML:
<article>
<p1>The text 1111, 2222, 3333 and 4444 are some values, 1111 another occurance.</p1>
<p1>The text 1111, 2222, 3333 and 4444 are some values</p1>
<p>The text 1111, 2222, 3333 and 4444 are some values</p>
<p1>The text aaaaa, bbbbb, ccccc and ddddd are another set of values</p1>
<p1>The text <i>aaaaa</i>, <b>bbbbb</b> and <c>ccccc</c> are in different form</p1>
</article>
XSLT 2.0:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="#*|node()">
<xsl:copy><xsl:apply-templates select="#* | node()"/></xsl:copy>
</xsl:template>
<xsl:template match="*/text()">
<xsl:call-template name="tempFindReplace">
<xsl:with-param name="pText1" select="."/>
</xsl:call-template>
</xsl:template>
<xsl:template name="tempFindReplace">
<xsl:param name="pText1"/>
<xsl:if test="string-length($pText1) > 0">
<xsl:choose>
<xsl:when test="ancestor::p1">
<xsl:choose>
<xsl:when test="contains($pText1, '1111')">
<xsl:value-of select="substring-before($pText1,'1111')"/><xsl:text>Alpha1</xsl:text>
<xsl:call-template name="tempFindReplace"><xsl:with-param name="pText1" select="substring-after($pText1, '1111')"/></xsl:call-template></xsl:when>
<xsl:when test="contains($pText1, '2222')">
<xsl:value-of select="substring-before($pText1,'2222')"/><xsl:text>Alpha2</xsl:text>
<xsl:call-template name="tempFindReplace"><xsl:with-param name="pText1" select="substring-after($pText1, '2222')"/></xsl:call-template></xsl:when>
<xsl:when test="contains($pText1, '3333')">
<xsl:value-of select="substring-before($pText1,'3333')"/><xsl:text>Alpha3</xsl:text>
<xsl:call-template name="tempFindReplace"><xsl:with-param name="pText1" select="substring-after($pText1, '3333')"/></xsl:call-template></xsl:when>
<xsl:when test="contains($pText1, '4444')">
<xsl:value-of select="substring-before($pText1,'4444')"/><xsl:text>Alpha4</xsl:text>
<xsl:call-template name="tempFindReplace"><xsl:with-param name="pText1" select="substring-after($pText1, '4444')"/></xsl:call-template></xsl:when>
<xsl:when test="contains($pText1, 'aaaaa')">
<xsl:value-of select="substring-before($pText1,'aaaaa')"/><xsl:text>Beta1</xsl:text>
<xsl:call-template name="tempFindReplace"><xsl:with-param name="pText1" select="substring-after($pText1, 'aaaaa')"/></xsl:call-template></xsl:when>
<xsl:when test="contains($pText1, 'bbbbb')">
<xsl:value-of select="substring-before($pText1,'bbbbb')"/><xsl:text>Beta2</xsl:text>
<xsl:call-template name="tempFindReplace"><xsl:with-param name="pText1" select="substring-after($pText1, 'bbbbb')"/></xsl:call-template></xsl:when>
<xsl:when test="contains($pText1, 'ccccc')">
<xsl:value-of select="substring-before($pText1,'ccccc')"/><xsl:text>Beta3</xsl:text>
<xsl:call-template name="tempFindReplace"><xsl:with-param name="pText1" select="substring-after($pText1, 'ccccc')"/></xsl:call-template></xsl:when>
<xsl:when test="contains($pText1, 'ddddd')">
<xsl:value-of select="substring-before($pText1,'ddddd')"/><xsl:text>Beta4</xsl:text>
<xsl:call-template name="tempFindReplace"><xsl:with-param name="pText1" select="substring-after($pText1, 'ddddd')"/></xsl:call-template></xsl:when>
<xsl:otherwise>
<xsl:value-of select="substring($pText1,1,1)"/>
<xsl:call-template name="tempFindReplace">
<xsl:with-param name="pText1" select="substring($pText1, 2)"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Required Result:
<article>
<p1>The text Alpha1, Alpha2, Alpha3 and Alpha4 are some values, Alpha1 another occurance.</p1><!-- Alpha1 only replacing, but other texts also required change, I assume here failing because of 1111 appearing twice-->
<p1>The text Alpha1, Alpha2, Alpha3 and Alpha4 are some values</p1>
<p>The text 1111, 2222, 3333 and 4444 are some values</p>
<p1>The text Beta1, Beta2, Beta3 and Beta4 are another set of values</p1>
<p1>The text <i>Beta1</i>, <b>Beta2</b> and <c>Beta3</c> are in different form</p1>
</article>
I continue to think you can use the replace function repeatedly, for instance in XSLT 3 with xsl:iterate:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:param name="replacements" as="array(xs:string)*"
select="['1111', 'Alpha1'], ['2222', 'Alpha2'], ['3333', 'Alpha3'], ['4444', 'Alpha4'],
['aaaaa', 'Beta1'], ['bbbbb', 'Beta2'], ['ccccc', 'Beta3'], ['ddddd', 'Beta4'] "/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="article/*[not(self::p)]//text()">
<xsl:iterate select="$replacements">
<xsl:param name="text" select="."/>
<xsl:on-completion>
<xsl:value-of select="$text"/>
</xsl:on-completion>
<xsl:next-iteration>
<xsl:with-param name="text" select="replace($text, .(1), .(2))"/>
</xsl:next-iteration>
</xsl:iterate>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/bwdwrL
XSLT 2:
called template twice, and got the result.
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="#*|node()">
<xsl:copy><xsl:apply-templates select="#* | node()"/></xsl:copy>
</xsl:template>
<xsl:template match="*[ancestor-or-self::*[matches(name(), '^(p1|p2|p3)$')]]/text()">
<xsl:variable name="var1">
<xsl:call-template name="tempFindReplace">
<xsl:with-param name="pText1" select="."/>
</xsl:call-template>
</xsl:variable>
<xsl:call-template name="tempFindReplace">
<xsl:with-param name="pText1" select="$var1"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="tempFindReplace">
<xsl:param name="pText1"/>
<xsl:if test="string-length($pText1) > 0">
<xsl:choose>
<xsl:when test="contains($pText1, '1111')">
<xsl:value-of select="substring-before($pText1,'1111')"/><xsl:text>Alpha1</xsl:text>
<xsl:call-template name="tempFindReplace"><xsl:with-param name="pText1" select="substring-after($pText1, '1111')"/></xsl:call-template></xsl:when>
<xsl:when test="contains($pText1, '2222')">
<xsl:value-of select="substring-before($pText1,'2222')"/><xsl:text>Alpha2</xsl:text>
<xsl:call-template name="tempFindReplace"><xsl:with-param name="pText1" select="substring-after($pText1, '2222')"/></xsl:call-template></xsl:when>
<xsl:when test="contains($pText1, '3333')">
<xsl:value-of select="substring-before($pText1,'3333')"/><xsl:text>Alpha3</xsl:text>
<xsl:call-template name="tempFindReplace"><xsl:with-param name="pText1" select="substring-after($pText1, '3333')"/></xsl:call-template></xsl:when>
<xsl:when test="contains($pText1, '4444')">
<xsl:value-of select="substring-before($pText1,'4444')"/><xsl:text>Alpha4</xsl:text>
<xsl:call-template name="tempFindReplace"><xsl:with-param name="pText1" select="substring-after($pText1, '4444')"/></xsl:call-template></xsl:when>
<xsl:when test="contains($pText1, 'aaaaa')">
<xsl:value-of select="substring-before($pText1,'aaaaa')"/><xsl:text>Beta1</xsl:text>
<xsl:call-template name="tempFindReplace"><xsl:with-param name="pText1" select="substring-after($pText1, 'aaaaa')"/></xsl:call-template></xsl:when>
<xsl:when test="contains($pText1, 'bbbbb')">
<xsl:value-of select="substring-before($pText1,'bbbbb')"/><xsl:text>Beta2</xsl:text>
<xsl:call-template name="tempFindReplace"><xsl:with-param name="pText1" select="substring-after($pText1, 'bbbbb')"/></xsl:call-template></xsl:when>
<xsl:when test="contains($pText1, 'ccccc')">
<xsl:value-of select="substring-before($pText1,'ccccc')"/><xsl:text>Beta3</xsl:text>
<xsl:call-template name="tempFindReplace"><xsl:with-param name="pText1" select="substring-after($pText1, 'ccccc')"/></xsl:call-template></xsl:when>
<xsl:when test="contains($pText1, 'ddddd')">
<xsl:value-of select="substring-before($pText1,'ddddd')"/><xsl:text>Beta4</xsl:text>
<xsl:call-template name="tempFindReplace"><xsl:with-param name="pText1" select="substring-after($pText1, 'ddddd')"/></xsl:call-template></xsl:when>
<xsl:otherwise>
<xsl:value-of select="substring($pText1,1,1)"/>
<xsl:call-template name="tempFindReplace">
<xsl:with-param name="pText1" select="substring($pText1, 2)"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
I have this flat xml. i need to group the contents on h1/title and copy all following para's until next h1/title pattern if exists else add empty para.
Source XML:
<Element>
<h1>
<title>Name1</title>
</h1>
<h1>
<title>Name2</title>
</h1>
<para>Test1</para>
<para>Test2</para>
<h1>
<title>Name3</title>
</h1>
<para>Test3</para>
<para>Test4</para>
</Element>
I want the output like below.
<Element>
<group>
<h1>
<title>Name1</title>
</h1>
<para> </para>
</group>
<group>
<h1>
<title>Name2</title>
</h1>
<para>Test1</para>
<para>Test2</para>
</group>
<group>
<h1>
<title>Name3</title>
</h1>
<para>Test3</para>
<para>Test4</para>
</group>
</Element>
so far I have tried following template, it does not copy following para's.
<xsl:template match="h1">
<group>
<xsl:copy>
<xsl:for-each-group select="*" group-starting-with="h1">
<xsl:choose>
<xsl:when test="self::h1">
<group>
<xsl:apply-templates select="current-group()"/>
<xsl:apply-templates select="following-sibling::para[not(following::h1)]"/>
</group>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:copy>
</group>
</xsl:template>
I would suggest to group the children of the Element element and then of course inside of the for-each-group you can simply check whether there is no second group item to add the empty para:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output indent="yes"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Element">
<xsl:copy>
<xsl:for-each-group select="*" group-starting-with="h1">
<xsl:choose>
<xsl:when test="self::h1">
<group>
<xsl:apply-templates select="current-group()"/>
<xsl:if test="not(current-group()[2])">
<para/>
</xsl:if>
</group>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:transform>
Online at http://xsltransform.net/naZXpX7.
Is there any function to convert roman number to integer like format-number function can change integer number to roman number. As i am working on conversion a roman number to integer. if there is no function than i have to handle this in templates.
I have handle this through writing own function, but there is an issue that it is not validate the input value such as (VII or IVII is same) but output is correct.
XSLT
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:number="http://dummy" version="2.0" >
<xsl:output method="text"/>
<xsl:template match="/">
(<xsl:value-of select="number:RomanToInteger('MMXVII', 0)"/>)
</xsl:template>
<xsl:function name="number:RomanToInteger">
<xsl:param name="romannumber"/>
<xsl:param name="followingvalue"/>
<xsl:choose>
<xsl:when test="ends-with($romannumber,'CM')">
<xsl:value-of select="900 + number:RomanToInteger(substring($romannumber,1,string-length($romannumber)-2), 900)"/>
</xsl:when>
<xsl:when test="ends-with($romannumber,'M')">
<xsl:value-of select="1000+ number:RomanToInteger(substring($romannumber,1,string-length($romannumber)-1), 1000)"/>
</xsl:when>
<xsl:when test="ends-with($romannumber,'CD')">
<xsl:value-of select="400+ number:RomanToInteger(substring($romannumber,1,string-length($romannumber)-2), 400)"/>
</xsl:when>
<xsl:when test="ends-with($romannumber,'D')">
<xsl:value-of select="500+ number:RomanToInteger(substring($romannumber,1,string-length($romannumber)-1), 500)"/>
</xsl:when>
<xsl:when test="ends-with($romannumber,'XC')">
<xsl:value-of select="90+ number:RomanToInteger(substring($romannumber,1,string-length($romannumber)-2), 90)"/>
</xsl:when>
<xsl:when test="ends-with($romannumber,'C')">
<xsl:value-of select="(if(100 ge number($followingvalue)) then 100 else -100)+ number:RomanToInteger(substring($romannumber,1,string-length($romannumber)-1), 100)"/>
</xsl:when>
<xsl:when test="ends-with($romannumber,'XL')">
<xsl:value-of select="40+ number:RomanToInteger(substring($romannumber,1,string-length($romannumber)-2), 40)"/>
</xsl:when>
<xsl:when test="ends-with($romannumber,'L')">
<xsl:value-of select="50+ number:RomanToInteger(substring($romannumber,1,string-length($romannumber)-1), 50)"/>
</xsl:when>
<xsl:when test="ends-with($romannumber,'IX')">
<xsl:value-of select="9+ number:RomanToInteger(substring($romannumber,1,string-length($romannumber)-2), 9)"/>
</xsl:when>
<xsl:when test="ends-with($romannumber,'X')">
<xsl:value-of select="(if(10 ge number($followingvalue)) then 10 else -10) + number:RomanToInteger(substring($romannumber,1,string-length($romannumber)-1), 10)"/>
</xsl:when>
<xsl:when test="ends-with($romannumber,'IV')">
<xsl:value-of select="4+ number:RomanToInteger(substring($romannumber,1,string-length($romannumber)-2), 4)"/>
</xsl:when>
<xsl:when test="ends-with($romannumber,'V')">
<xsl:value-of select="5+ number:RomanToInteger(substring($romannumber,1,string-length($romannumber)-1), 5)"/>
</xsl:when>
<xsl:when test="ends-with($romannumber,'I')">
<xsl:value-of select="(if(1 ge number($followingvalue)) then 1 else -1)+ number:RomanToInteger(substring($romannumber,1,string-length($romannumber)-1), 1)"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="0"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
</xsl:stylesheet>
Input:
<DOINUM>10.1080/14772019.2016.1274343</DOINUM>
Output:
No needed 'italic' element inside the 'pub-id' element
<pub-id pub-id-type="doi"><italic>10.1080/14772019.2016.1274343</italic></pub-id>
Xslt Code:
we creat 'pub-id' element below code
<pub-id pub-id-type="doi">
<xsl:apply-templates/>
</pub-id>
we create 'italic' element here, but 'italic' element not allowed inside the 'pub-id element, please give suggestion how can remove 'italic' element inside the 'pub-id' element.
<xsl:template match="IT" mode="demote">
<xsl:param name="content"/>
<xsl:apply-templates select=".." mode="demote">
<xsl:with-param name="content">
<xsl:choose>
<xsl:when test="normalize-space($content)">
<!-- providing 'italic' only if there's something
to put into italics -->
<italic>
<xsl:copy-of select="$content"/>
</italic>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="$content"/>
</xsl:otherwise>
</xsl:choose>
</xsl:with-param>
</xsl:apply-templates>
</xsl:template>