Copy matching elements under one group element - xslt-2.0

I have a flat xml and I need to copy all matching elements under one element.
In input xml there are title elements which can randomly appear in xml. I want to put them under one element. Any help?
Input:
<root>
<element>
<para>Text 11.</para>
<para>Text 22.</para>
</element>
<title number="1">
<title.block>Title1</title.block>
<para>Text 33.</para>
<para>Text 44.</para>
</title>
<title number="2">
<title.block>Title2</title.block>
</title>
<element1>
<para>Some Text</para>
</element1>
<title number="3">
<title.block>Title2</title.block>
<para>Text 55.</para>
</title>
<result>
<para>Some Text</para>
</result>
</root>
desired output is:
<root>
<element>
<para>Text 11.</para>
<para>Text 22.</para>
</element>
<title.group>
<title number="1">
<title.block>Title1</title.block>
<para>Text 33.</para>
<para>Text 44.</para>
</title>
<title number="2">
<title.block>Title2</title.block>
</title>
<title number="3">
<title.block>Title2</title.block>
<para>Text 55.</para>
</title>
</title.group>
<element1>
<para>Some Text</para>
</element1>
<result>
<para>Some Text</para>
</result>
</root>

Simply write a template for the first title that creates the group and copies that title and all following siblings into the group:
<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="root/title[1]">
<title-group>
<xsl:copy-of select="., following-sibling::title"/>
</title-group>
</xsl:template>
<xsl:template match="root/title[position() gt 1]"/>
</xsl:transform>
http://xsltransform.net/a9Giwu

Related

Two XSL files need single final output file

I have a input file and two XSL files test1.xsl, test2.xsl
test1.xsl file transforming on input file and generating test1-output.xml
test2.xsl file transforming on test1-output.xml and generating the final output
Requirement:
I am using XSLT 2.0
I want run at a time both xslt files transform on input file and generate the final output.
How to do this requirement, Please suggest!
Input file:
<?xml version="1.0" encoding="UTF-8"?>
<k>
<page>content here</page>
<page1>content here</page1>
</k>
test1.xsl file:
<?xml version="1.0"qqq encoding="UTF-8"?>
<xsl:stylesheet xmqlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output indent="yes" method="xml"/>
<xsl:template match="#*| node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="page">
<page>
<kita>
<xsl:apply-templates/>
</kita>
</page>
</xsl:template>
</xsl:stylesheet>
output of test1.xsl
<?xml version="1.0" encoding="UTF-8"?>
<k>
<page>
<kita>content here</kita>
</page>
<page1>content here</page1>
</k>
test2.xsl
<?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"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output indent="yes" method="xml"/>
<xsl:template match="#*| node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="kita">
<kita>
<kita1>
<xsl:apply-templates/>
</kita1>
</kita>
</xsl:template>
</xsl:stylesheet>
This is my final xml output from the 2nd XSLT file:
<?xml version="1.0" encoding="UTF-8"?>
<k>
<page>
<kita>
<kita1>content here</kita1>
</kita>
</page>
<page1>content here</page1>
</k>
Thanks in advance
In XSLT 3 you could write a stylesheet with two parameters calling fn:transform twice e.g.
<xsl:param name="xslt1" as="document-node()"/>
<xsl:param name="xslt2" as="document-node()"/>
<xsl:template match="/">
<xsl:sequence
select="
transform(map {
'stylesheet-node' : $xslt1,
'source-node' : .
})?output ! transform(map {
'stylesheet-node' : $xslt2,
'source-node' : .
})?output"/>
</xsl:template>
or if you want to pass in the file URIs
<xsl:param name="xslt1" as="xs:string">test1.xsl</xsl:param>
<xsl:param name="xslt2" as="xs:string">test2.xsl</xsl:param>
<xsl:template match="/">
<xsl:sequence
select="
transform(map {
'stylesheet-node' : doc($xslt1),
'source-node' : .
})?output ! transform(map {
'stylesheet-node' : doc($xslt2),
'source-node' : .
})?output"/>
</xsl:template>

Aggregate nodes based on conditon under new parent

I have an given XML and I want to convert it in new xml and want to aggregate nodes based on status and orderId.
<?xml version="1.0" encoding="utf-8"?>
<OrderStatusUpdate>
<OrderStatusEvents>
<OrderStatusEvent>
<StoreCode>store1</StoreCode>
<OrderId>Order1</OrderId>
<ItemId>Item1</ItemId>
<OrderStatusDetails>
<OrderStatusDetail>
<OrderStatusEventTimeStamp>2017-03-19 03:37:05</OrderStatusEventTimeStamp>
<StatusName>Cancelled</StatusName>
</OrderStatusDetail>
</OrderStatusDetails>
</OrderStatusEvent>
<OrderStatusEvent>
<StoreCode>Store1</StoreCode>
<OrderId>Order1</OrderId>
<ItemId>Item2</ItemId>
<OrderStatusDetails>
<OrderStatusDetail>
<OrderStatusEventTimeStamp>2017-03-19 03:48:35</OrderStatusEventTimeStamp>
<StatusName>Cancelled</StatusName>
</OrderStatusDetail>
</OrderStatusDetails>
</OrderStatusEvent>
<OrderStatusEvent>
<StoreCode>Store1</StoreCode>
<OrderId>Order1</OrderId>
<ItemId>Item3</ItemId>
<OrderStatusDetails>
<OrderStatusDetail>
<OrderStatusEventTimeStamp>2017-03-19 03:48:35</OrderStatusEventTimeStamp>
<StatusName>Shipped</StatusName>
</OrderStatusDetail>
</OrderStatusDetails>
</OrderStatusEvent>
<OrderStatusEvent>
<StoreCode>Store1</StoreCode>
<OrderId>Order2</OrderId>
<ItemId>Item1</ItemId>
<OrderStatusDetails>
<OrderStatusDetail>
<OrderStatusEventTimeStamp>2017-03-19 03:48:35</OrderStatusEventTimeStamp>
<StatusName>Cancelled</StatusName>
</OrderStatusDetail>
</OrderStatusDetails>
</OrderStatusEvent>
</OrderStatusEvents>
</OrderStatusUpdate>
And I want an output like this. Here I am grouping elements based on status and orderId.
<Orders>
<group name="CANCELLED">
<STATUS ID="CANCELLED" DESCRIPTION="Goods Cancelled">
<ORDER ID="Order1">
<ORDER_ITEM item="item1" />
<ORDER_ITEM item="item2" />
</ORDER>
</STATUS>
<STATUS ID="CANCELLED" DESCRIPTION="Goods Cancelled">
<ORDER ID="Order2">
<ORDER_ITEM item="item1" />
</ORDER>
</STATUS>
</group>
<group name="SHIPPED">
<STATUS ID="SHIPPED" DESCRIPTION="Goods SHIPPED">
<ORDER ID="Order1">
<ORDER_ITEM item="item3" />
</ORDER>
</STATUS>
<group>
</Orders>
I am using the following xslt and it is working fine. Is there any way to improve this.
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes" />
<xsl:template match="OrderStatusUpdate/OrderStatusEvents">
<Orders>
<xsl:for-each-group select="OrderStatusEvent" group-by="OrderStatusDetails/OrderStatusDetail/StatusName">
<xsl:variable name="group-name" select="current-grouping-key()" />
<group name="{current-grouping-key()}">
<xsl:for-each-group select="current-group()" group-by="OrderId">
<xsl:variable name="order-id" select="current-grouping-key()" />
<xsl:element name="STATUS">
<xsl:attribute name="ID"><xsl:value-of select="$group-name" /></xsl:attribute>
<xsl:attribute name="DESCRIPTION">Goods <xsl:value-of select="$group-name" /></xsl:attribute>
<xsl:element name="ORDER">
<xsl:attribute name="ID"><xsl:value-of select="$order-id" /></xsl:attribute>
<xsl:for-each select="current-group()">
<xsl:if test="$group-name = 'Shipped'">
<xsl:call-template name="Shipped">
<xsl:with-param name="nodes">
<xsl:copy-of select="." />
</xsl:with-param>
</xsl:call-template>
</xsl:if>
<xsl:if test="$group-name = 'Cancelled'">
<xsl:call-template name="Cancelled">
<xsl:with-param name="nodes">
<xsl:copy-of select="." />
</xsl:with-param>
</xsl:call-template>
</xsl:if>
</xsl:for-each>
</xsl:element>
</xsl:element>
</xsl:for-each-group>
</group>
</xsl:for-each-group>
</Orders>
</xsl:template>
<xsl:template name="Shipped">
<xsl:param name="nodes">
</xsl:param>
<xsl:element name="ORDER_ITEM">
<xsl:attribute name="ID"><xsl:value-of select="$nodes/OrderStatusEvent/ItemId" /></xsl:attribute>
</xsl:element>
</xsl:template>
<xsl:template name="Cancelled">
<xsl:param name="nodes"></xsl:param>
<xsl:element name="ORDER_ITEM">
<xsl:attribute name="ID"><xsl:value-of select="$nodes/OrderStatusEvent/ItemId" /></xsl:attribute>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
It is easier to use literal result elements and attribute value templates as long as you don't need to compute element or attribute names at run-time and I don't think you need the two templates and call-template, it suffices to use
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output omit-xml-declaration="yes" indent="yes" />
<xsl:template match="OrderStatusUpdate/OrderStatusEvents">
<Orders>
<xsl:for-each-group select="OrderStatusEvent" group-by="OrderStatusDetails/OrderStatusDetail/StatusName">
<xsl:variable name="group-name" select="current-grouping-key()" />
<group name="{current-grouping-key()}">
<xsl:for-each-group select="current-group()" group-by="OrderId">
<xsl:variable name="order-id" select="current-grouping-key()" />
<STATUS ID="{$group-name}" DESCRIPTION="Goods {$group-name}">
<ORDER ID="{$order-id}">
<xsl:apply-templates select="current-group()"/>
</ORDER>
</STATUS>
</xsl:for-each-group>
</group>
</xsl:for-each-group>
</Orders>
</xsl:template>
<xsl:template match="OrderStatusEvent">
<ORDER_ITEM ID="{ItemId}"/>
</xsl:template>
</xsl:stylesheet>

XSLT 2.0 Group Node-set checking descendant attributes

I have the following node-set fragment:
<category value="Library">
<category value="PACS">
<category value="IMPAX (PACS)">
<category value="Reporting"/>
</category>
</category>
</category>
<category value="Library">
<category value="Enterprise Imaging">
<category value="Desktops"/>
</category>
</category>
<category value="Library">
<category value="PACS">
<category value="IMPAX (PACS)"/>
</category>
</category>
Which is generated by the following:
<xsl:template name="categories">
<xsl:param name="topicmeta"/>
<xsl:variable name="VarCategories">
<xsl:for-each select="map/topicmeta/category">
<xsl:if test="contains(./data/#value, 'Library')">
<xsl:if
test="string-length(./data/#value) - string-length(translate(./data/#value, '/', '')) > 1">
<xsl:call-template name="category">
<xsl:with-param name="category" select="./data/#value"/>
</xsl:call-template>
</xsl:if>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:call-template name="outputCategories">
<xsl:with-param name="categories" select="$VarCategories"/>
</xsl:call-template>
</xsl:template>
I need to output:
<category value="Library">
<category value="PACS">
<category value="IMPAX (PACS)">
<category value="Reporting"/>
</category>
</category>
<category value="Enterprise Imaging">
<category value="Desktops"/>
</category>
</category>
I am trying to use the for-each-group
<xsl:template name="outputCategories">
<xsl:param name="categories"/>
<xsl:element name="categories">
<xsl:for-each-group select="$categories/*" group-adjacent="#value">
<xsl:sort select="#value"></xsl:sort>
<xsl:copy-of select="." />
</xsl:for-each-group>
</xsl:element>
</xsl:template>
Which gives me:
<category value="Library">
<category value="PACS">
<category value="IMPAX (PACS)">
<category value="Reporting"/>
</category>
</category>
I need to check each level and group each distinct value.
Put your code into a recursive function:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="mf xs">
<xsl:output indent="yes"/>
<xsl:function name="mf:group" as="element(category)*">
<xsl:param name="categories" as="element(category)*"/>
<xsl:for-each-group select="$categories" group-by="#value">
<category value="{current-grouping-key()}">
<xsl:sequence select="mf:group(current-group()/category)"/>
</category>
</xsl:for-each-group>
</xsl:function>
<xsl:param name="cats">
<category value="Library">
<category value="PACS">
<category value="IMPAX (PACS)">
<category value="Reporting"/>
</category>
</category>
</category>
<category value="Library">
<category value="Enterprise Imaging">
<category value="Desktops"/>
</category>
</category>
<category value="Library">
<category value="PACS">
<category value="IMPAX (PACS)"/>
</category>
</category>
</xsl:param>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:sequence select="mf:group($cats/category)"/>
</xsl:template>
</xsl:transform>
Online at http://xsltransform.net/3NJ38ZB.
If you need the sorting as well then change the function to e.g.
<xsl:function name="mf:group" as="element(category)*">
<xsl:param name="categories" as="element(category)*"/>
<xsl:for-each-group select="$categories" group-by="#value">
<xsl:sort select="current-grouping-key()"/>
<category value="{current-grouping-key()}">
<xsl:sequence select="mf:group(current-group()/category)"/>
</category>
</xsl:for-each-group>
</xsl:function>
As for the sample you have linked to in your comment, it puts its created category elements in the FO namespace, you either have to avoid that by doing
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns="http://www.w3.org/1999/XSL/Format"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:exsl="http://exslt.org/common"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="xs exsl mf">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="status"/>
<xsl:param name="draft"/>
<xsl:template match="/">
<index>
<xsl:call-template name="categories"> </xsl:call-template>
</index>
</xsl:template>
<xsl:template name="categories">
<xsl:param name="topicmeta"/>
<xsl:variable name="VarCategories">
<xsl:for-each select="map/topicmeta/category">
<xsl:if test="contains(./data/#value, 'Library')">
<xsl:if
test="string-length(./data/#value) - string-length(translate(./data/#value, '/', '')) > 1">
<xsl:call-template name="category">
<xsl:with-param name="category" select="./data/#value"/>
</xsl:call-template>
</xsl:if>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="mf:group($VarCategories/category)"/>
</xsl:template>
<xsl:template name="category" xmlns="">
<xsl:param name="category"/>
<xsl:if test="string-length($category) > 0">
<xsl:element name="category">
<xsl:attribute name="value">
<xsl:choose>
<xsl:when test="substring-before($category, '/') = ''">
<xsl:value-of select="$category"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="substring-before($category, '/')"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:call-template name="category">
<xsl:with-param name="category" select="substring-after($category, '/')"/>
</xsl:call-template>
</xsl:element>
</xsl:if>
</xsl:template>
<xsl:function name="mf:group" as="element(category)*" xmlns="">
<xsl:param name="categories" as="element(category)*"/>
<xsl:for-each-group select="$categories" group-by="#value">
<xsl:sort select="current-grouping-key()"/>
<category value="{current-grouping-key()}">
<xsl:sequence select="mf:group(current-group()/category)"/>
</category>
</xsl:for-each-group>
</xsl:function>
</xsl:stylesheet>
or you have to make sure the paths in the function select the elements in that namespace:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns="http://www.w3.org/1999/XSL/Format"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:exsl="http://exslt.org/common"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="xs exsl mf">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="status"/>
<xsl:param name="draft"/>
<xsl:template match="/">
<index>
<xsl:call-template name="categories"> </xsl:call-template>
</index>
</xsl:template>
<xsl:template name="categories">
<xsl:param name="topicmeta"/>
<xsl:variable name="VarCategories">
<xsl:for-each select="map/topicmeta/category">
<xsl:if test="contains(./data/#value, 'Library')">
<xsl:if
test="string-length(./data/#value) - string-length(translate(./data/#value, '/', '')) > 1">
<xsl:call-template name="category">
<xsl:with-param name="category" select="./data/#value"/>
</xsl:call-template>
</xsl:if>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:sequence select="mf:group($VarCategories/*)"/>
</xsl:template>
<xsl:template name="category">
<xsl:param name="category"/>
<xsl:if test="string-length($category) > 0">
<xsl:element name="category">
<xsl:attribute name="value">
<xsl:choose>
<xsl:when test="substring-before($category, '/') = ''">
<xsl:value-of select="$category"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="substring-before($category, '/')"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:call-template name="category">
<xsl:with-param name="category" select="substring-after($category, '/')"/>
</xsl:call-template>
</xsl:element>
</xsl:if>
</xsl:template>
<xsl:function name="mf:group" as="element(category)*" xpath-default-namespace="http://www.w3.org/1999/XSL/Format">
<xsl:param name="categories" as="element(category)*"/>
<xsl:for-each-group select="$categories" group-by="#value">
<xsl:sort select="current-grouping-key()"/>
<category value="{current-grouping-key()}">
<xsl:sequence select="mf:group(current-group()/category)"/>
</category>
</xsl:for-each-group>
</xsl:function>
</xsl:stylesheet>

Extracting value from External xml based on some rule in xsl

This is input xml input.xml
<root>
<bodytext>
<remotelink refptid="HKBL1.0001.lohk.CAP65">some text</remotelink>
<remotelink refptid="HKBL1.0001.lohk.CAP199999">some text</remotelink>
</bodytext>
</root>
This is Prop.xml
<?xml version="1.0" encoding="utf-8"?>
<properties>
<code dpsi="0BZG" docid="asdww">HKBL1.0001.lohk.CAP65</code>
<code dpsi="0BZH" docid="navin">HKBL1.0002.aohk.CAP383</code>
<code no="3">345</code>
</properties>
This is desired output
<root>
<bodytext>
<remotelink refptid="HKBL1.0001.lohk.CAP65" dpsi="0BZG" docid="asdww">some text</remotelink>
<remotelink refptid="HKBL1.0001.lohk.CAP199999">some text</remotelink>
</bodytext>
</root>
IF prop.xml code/text matches remotelink/#refptid than copy attribute of prop.xml to remotelink otherwise no changes in remotelink.
This is the XSLT I have written. So far I am not getting result for unmatched condition:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xlsx="http://www.stylusstudio.com/XSLT/XLSX" xmlns:spml="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:saxon="http://saxon.sf.net/" version="2.0">
<xsl:template match="#*|node()" name="root">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="remotelink[#service='DOC-ID']" name="t-remote">
<xsl:variable name="refptid" select="./#refpt"/>
<xsl:variable name="path" select="doc('file:/C:/Users/DalalNS/Desktop/xslt/prop.xml')"/>
<xsl:for-each select="$path/properties/code">
<xsl:choose>
<xsl:when test="./text()=$refptid">
<xsl:element name="remotelink">
<xsl:attribute name="DOC-ID" select="./#docid"/>
<xsl:attribute name="dpsi" select="./#dpsi"/>
<xsl:attribute name="refpt" select="$refptid"/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<xsl:if test="./#docrefid"/>
</xsl:template>
</xsl:stylesheet>
<xsl:template match="remotelink[#service='DOC-ID']"> will never never be triggered, there's no service attribute on the <remotelink> element. Moreover, you don't retrieve the correct attribute (refpt instead of refptid)
This XSL transformation should do the job:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xlsx="http://www.stylusstudio.com/XSLT/XLSX" xmlns:spml="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:saxon="http://saxon.sf.net/" version="2.0">
<xsl:variable name="props.doc" select="doc('file:/C:/Users/DalalNS/Desktop/xslt/prop.xml')/properties" />
<xsl:template match="#*|node()" name="root">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="remotelink" name="t-remote">
<xsl:variable name="refptid" select="./#refptid"/>
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:if test="$props.doc/code[. = $refptid]">
<xsl:apply-templates select="$props.doc/code[. = $refptid]/#*"/>
</xsl:if>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
This is the result of the transformation:
<?xml version="1.0" encoding="UTF-8"?><root>
<bodytext>
<remotelink refptid="HKBL1.0001.lohk.CAP65" dpsi="0BZG" docid="asdww">some text</remotelink>
<remotelink refptid="HKBL1.0001.lohk.CAP199999">some text</remotelink>
</bodytext>
</root>
I would simply define a global parameter or variable <xsl:variable name="path" select="doc('file:/C:/Users/DalalNS/Desktop/xslt/prop.xml')"/>, then set up a key <xsl:key name="prop" match="code" use="."/>, and then use that in a template
<xsl:template match="remotelink[key('prop', #refptid, $path)]">
<xsl:copy>
<xsl:copy-of select="key('prop', #refptid, $path)/#*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
that, together with your first template, should suffice.

Splitfunction gives troubles

I'm facing the following problem or challenge.
I've a an element in my source XML which can have 450 characters.
With my xslt I want to transform this into chunks of 75 characters.
...
<T61>
<parentInfo>SomeInfo</parentInfo>
<T86>
<info>abcdefghijklmnopqrstuvwxyz01234567890abcdefghijklmnopqrstuvwxyz01234567890</info>
</T86>
</T61>
...
The output I generate should look something like:
<T31>
<x>abcdefghijklmnopqrstuvwxyz01234567890</x>
</T31>
<T31>
<x>abcdefghijklmnopqrstuvwxyz01234567890</x>
</T31>
In my code I use an template for T61 which does his work.
I thought to create another template for T86 and call this from inside the T61 template but this seems not to work because I've the complete string. I created an function which could split up the string in parts of 75. But the outcome of the function is still the complete string.
I used a function from an earlier post:
<xsl:function name="my:splitItUp" as="xs:string">
<xsl:param name="input" as="xs:string"/>
<xsl:param name="chunk-size" as="xs:integer"/>
<xsl:value-of>
<xsl:for-each-group select="string-to-codepoints($input)" group-by="(position() -1) idiv $chunk-size">
<xsl:sequence select="codepoints-to-string(current-group())"/>
</xsl:for-each-group>
</xsl:value-of>
</xsl:function>
...
<xsl:template match="T86">
<xsl:for-each select="my:splitItUp(info, 75)">
<T31>
<communication>
<xsl:value-of select="." />
</communication>
</T31>
</xsl:for-each>
</xsl:template>
This structure always result in a complete string. In debug I see it split it up but it concatenates the result together. Can I somehow come out of the function?
Best Regards Dirk
Please have a look this XSLT where you need to set <xsl:param name="stringRequired" select="xs:integer(13)"/> to chunk text:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes" encoding="utf-8"/>
<xsl:param name="XML">
<info>abcdefghijklmnopqrstuvwxyz01234567890abcdefghijklmnopqrstuvwxyz01234567890</info>
</xsl:param>
<xsl:param name="stringRequired" select="xs:integer(13)"/>
<xsl:param name="XMLLenfgh" select="string-length($XML)"/>
<xsl:template match="/">
<xsl:choose>
<xsl:when test="$XMLLenfgh gt $stringRequired">
<xsl:call-template name="getPart"/>
</xsl:when>
<xsl:otherwise>
<T31>
<x>
<xsl:value-of select="$XML/info"/>
</x>
</T31>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="getPart">
<xsl:param name="XML" select="$XML"/>
<xsl:param name="stringRequired" select="$stringRequired"/>
<xsl:param name="XMLLenfgh" select="$XMLLenfgh"/>
<xsl:message>
<xsl:value-of select="$XML"/>
</xsl:message>
<xsl:if test="$XMLLenfgh gt $stringRequired">
<T>
<x>
<xsl:value-of select="substring($XML,1,$stringRequired)"/>
</x>
</T>
<xsl:call-template name="getPart">
<xsl:with-param name="XML"
select="substring($XML,string-length(substring($XML,1,$stringRequired)))"/>
<xsl:with-param name="XMLLenfgh"
select="string-length(substring($XML,string-length(substring($XML,1,$stringRequired))))"/>
<xsl:with-param name="stringRequired" select="$stringRequired"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
OUTPUT:
<T xmlns:xs="http://www.w3.org/2001/XMLSchema">
<x>abcdefghijklm</x>
</T>
<T xmlns:xs="http://www.w3.org/2001/XMLSchema">
<x>mnopqrstuvwxy</x>
</T>
<T xmlns:xs="http://www.w3.org/2001/XMLSchema">
<x>yz01234567890</x>
</T>
<T xmlns:xs="http://www.w3.org/2001/XMLSchema">
<x>0abcdefghijkl</x>
</T>
<T xmlns:xs="http://www.w3.org/2001/XMLSchema">
<x>lmnopqrstuvwx</x>
</T>
<T xmlns:xs="http://www.w3.org/2001/XMLSchema">
<x>xyz0123456789</x>
</T>

Resources