I have a source document:
<?xml version = "1.0" encoding = "UTF-8"?>
<Circuit revision="B" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Block name="Design">
<Data>
<Layer name="INDEX_4" Function="PLANE"></Layer>
<Layer name="INDEX_9" Function="CORE"></Layer>
<Group name="PRIMARY">
<SubGroup name="GROUP_PRIMARY">
<SubLayer Ref="INDEX_4" thickness="0.0350"></SubLayer>
<SubLayer Ref="INDEX_9" thickness="0.1000"></SubLayer>
</SubGroup>
</Group>
</Data>
</Block>
</Circuit>
This stylesheet using current() extracts the corresponding thickness:
<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:template match="/Circuit/Block/Data/Layer">
<xsl:element name="{name()}">
<xsl:attribute name="id">
<xsl:value-of select="#name"/>
</xsl:attribute>
<xsl:attribute name="Function">
<xsl:value-of select="#Function"/>
</xsl:attribute>
<xsl:value-of select="/Circuit/Block/Data/Group/SubGroup/SubLayer[#Ref=current()/#name]/#thickness"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Here's the second stylesheet to extract the PREVIOUS thickness value:
<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:template match="/Circuit/Block/Data/Layer">
<xsl:element name="{name()}">
<xsl:attribute name="id">
<xsl:value-of select="#name"/>
</xsl:attribute>
<xsl:attribute name="Function">
<xsl:value-of select="#Function"/>
</xsl:attribute>
<xsl:value-of select="/Circuit/Block/Data/Group/SubGroup/SubLayer[#Ref=preceding-sibling::*[1]/#name]/#thickness"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
In both cases I get this:
<?xml version="1.0" encoding="UTF-8"?>
<Layer id="INDEX_4" Function="PLANE">0.0350</Layer>
<Layer id="INDEX_9" Function="CORE">0.1000</Layer>
I tried the preceding-sibling to get the preceding value - I guess the question is "What is the context of the preceding-sibling?"
Is it the group with the Layer element or the group with the SubLayer element?
Thanks
Ralph B
Within any predicate the context item is the selected item in the step before the predicate so with SubLayer[#Ref=preceding-sibling::*[1]/#name] the context for both #Ref as well as preceding-sibling::*[1]/#name is the SubLayer element. If you want to select relative to the currently matched Layer element in the template you need to use current()/preceding-sibling::*[1]/#name inside the predicate.
Related
I have to generate the output in sequence and so I wanted to know how to access the variable defined under For-each loop/If condition and then value of select inside another for loop.
As per my example how to access partn and date3? Please help and suggest.
what is the concept for achieving the same..I have tried with-param as well, but didn't work for me.
XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:func="myfunc"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fn="http://www.w3.org/2005/xpath-functions" >
<xsl:output method="text" encoding="utf-8" />
<xsl:output omit-xml-declaration="yes" />
<xsl:param name="break" select="'
'" />
<xsl:template match="ZGS/ID">
<xsl:for-each select="E1">
<xsl:if test="PA = 'CE'">
<xsl:variable name="partn" select="PAN"/>
</xsl:if>
</xsl:for-each>
<xsl:for-each select="E13">
<xsl:if test="ID = 033">
<xsl:variable name="date3"
select="substring(DAT,3,8)"/>
</xsl:if>
</xsl:for-each>
<xsl:for-each select="E1E">
<xsl:text>823</xsl:text>
<xsl:text>03</xsl:text>
<xsl:for-each select="E1ED">
<xsl:if test="QU = 012 ">
<xsl:value-of select="BEL"/>
</xsl:if>
</xsl:for-each>
<xsl:value-of select="$partn"/>
<xsl:value-of select="$date3"/>
</xsl:for-each>
</xsl:template>
INPUT:
<?xml version='1.0' encoding='utf-8'?>
<ZGS>
<ID BEGIN="1">
<E1 SEGMENT="1">
<PA>AG</PA>
<NAME>ABC</NAME>
<SP>E</SP>
<AND>0004</AND>
</E1>
<E1 SEGMENT="1">
<PA>RE</PA>
<PAN>IUIOP</PAN>
<NAME>ABC1</NAME>
<SP>EQ</SP>
<AND>0005</AND>
<EKA3 SEGMENT="1">
<QU>009</QU>
</EKA3>
</E1>
<E1 SEGMENT="1">
<PA>CE</PA>
<PAN>PODW</PAN>
<NAME>ABC2</NAME>
<SP>EP</SP>
<AND>0006</AND>
</E1>
<E13 SEGMENT="1">
<ID>001</ID>
<DAT>20190329</DAT>
</E13>
<E13 SEGMENT="1">
<ID>002</ID>
<DAT>20190429</DAT>
</E13>
<E13 SEGMENT="1">
<IDD>033</IDD>
<DAT>20190529</DAT>
</E13>
<E1E>
<E1ED>
</E1ED>
<E1ED>
</E1ED>
</E1E>
In XSLT, variables once declared/defined, they cannot be changed. And exists only in the loop they are defined.
You might not need the xsl:for-each loop here. Instead the variables can be globally defined, so that you can use them where you want in your xslt.
You can try the following:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:func="myfunc"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:output method="text" encoding="utf-8" />
<xsl:output omit-xml-declaration="yes" />
<xsl:param name="break" select="'
'" />
<xsl:variable name="partn" select="/ZGS/ID/E1[PA = 'CE']/PAN" />
<xsl:variable name="date3" select="substring(/ZGS/ID/E13[ID = '033']/DAT,3,8)" />
<xsl:template match="ZGS/ID">
<xsl:for-each select="E1E">
<xsl:text>823</xsl:text>
<xsl:text>03</xsl:text>
<xsl:for-each select="E1ED">
<xsl:if test="QU = 012 ">
<xsl:value-of select="BEL" />
</xsl:if>
</xsl:for-each>
<xsl:value-of select="$partn" />
<xsl:value-of select="$date3" />
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/jyRYYiu
Using xsl:param, it can be achieved as
<xsl:param name="partn" select="/ZGS/ID/E1[PA = 'CE']/PAN" />
<xsl:param name="date3" select="substring(/ZGS/ID/E13[ID = '033']/DAT,3,8)" />
<xsl:template match="ZGS/ID">
<xsl:for-each select="E1E">
<xsl:text>823</xsl:text>
<xsl:text>03</xsl:text>
<xsl:for-each select="E1ED">
<xsl:if test="QU = 012 ">
<xsl:value-of select="BEL" />
</xsl:if>
</xsl:for-each>
<xsl:for-each select="$partn">
<xsl:value-of select="." />
</xsl:for-each>
<xsl:value-of select="$date3" />
</xsl:for-each>
</xsl:template>
https://xsltfiddle.liberty-development.net/jyRYYiu/1
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>
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.
below one is the XML input,
<?xml version="1.0" encoding="utf-8"?>
<GSK_Canonical_MESGX2>
<header SEGMENT="1">
<orderNumber>002001454979</orderNumber>
<batchNumber>0000617944</batchNumber>
<BOM SEGMENT="1">
<operationNumber>0030</operationNumber>
<phaseIndicator>0011</phaseIndicator>
</BOM>
<BOM SEGMENT="1">
<operationNumber>0040</operationNumber>
<phaseIndicator>0012</phaseIndicator>
</BOM>
<recipe SEGMENT="1">
<phase>0011</phase>
<parentOperation>0030</parentOperation>
<workcenter>MANUOHD1</workcenter>
</recipe>
<recipe SEGMENT="1">
<phase>0012</phase>
<parentOperation>0040</parentOperation>
<workcenter>COSTOHD1</workcenter>
</recipe>
</header>
</GSK_Canonical_MESGX2>
I have an below xslt,
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="http://exslt.org/common" xmlns:set="http://exslt.org/sets" xmlns:str="http://exslt.org/strings" xmlns:java="http://xml.apache.org/xslt/java" xmlns:saxon="http://saxon.sf.net/" exclude-result-prefixes="exsl set str java saxon">
<xsl:output method="text"/>
<xsl:variable name="VarHash" select="'#'"/>
<xsl:variable name="VarBreak" select="'
'"/>
<xsl:variable name="pipeFieldDelimiter" select="'\|'"/>
<xsl:template match="/">
<xsl:text>HEADER</xsl:text>
<xsl:value-of select="$VarHash"/>
<xsl:value-of select="GSK_Canonical_MESGX2/header/orderNumber"/>
<xsl:value-of select="$VarHash"/>
<xsl:value-of select="GSK_Canonical_MESGX2/header/batchNumber"/>
<xsl:value-of select="$VarBreak"/>
<xsl:for-each select="GSK_Canonical_MESGX2/header/BOM">
<!--GSK_Canonical_MESGX2/Header/BOM/OperationNumber = GSK_Canonical_MESGX2/header/recipe/parentOperation and GSK_Canonical_MESGX2/Header/BOM/phaseIndicator = GSK_Canonical_MESGX2/header/recipe/phase then <xsl:value-of select="GSK_Canonical_MESGX2/header/recipe/workcenter"/> This needs to be implemented for each line item of BOM tag -->
<xsl:if test="position() != last()">
<xsl:value-of select="$VarBreak"/>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
below one is the expected output,
HEADER#002001454979#0000617944
MANUOHD1
COSTOHD1
now need to implement for each BOM line item,we need to compare BOM with Recipe tags and select workcenter value if the condition satisfied.
Header/BOM/OperationNumber = header/recipe/parentOperation
and
Header/BOM/phaseIndicator = header/recipe/phase
then
<xsl:value-of select="GSK_Canonical_MESGX2/header/recipe/workcenter"/>
Please help me to achieve this.Thanks
This transformation:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:key name="kBomByPhaseAndOperation" match="BOM"
use="concat(operationNumber, '|', phaseIndicator)"/>
<xsl:template match=
"recipe[key('kBomByPhaseAndOperation',
concat(parentOperation, '|', phase))
]">
<xsl:value-of select="concat('
', workcenter)"/>
</xsl:template>
<xsl:template match="header">
<xsl:text>HEADER</xsl:text>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="orderNumber|batchNumber">
<xsl:value-of select="concat('#', .)"/>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
When applied on the provided source XML document:
<GSK_Canonical_MESGX2>
<header SEGMENT="1">
<orderNumber>002001454979</orderNumber>
<batchNumber>0000617944</batchNumber>
<BOM SEGMENT="1">
<operationNumber>0030</operationNumber>
<phaseIndicator>0011</phaseIndicator>
</BOM>
<BOM SEGMENT="1">
<operationNumber>0040</operationNumber>
<phaseIndicator>0012</phaseIndicator>
</BOM>
<recipe SEGMENT="1">
<phase>0011</phase>
<parentOperation>0030</parentOperation>
<workcenter>MANUOHD1</workcenter>
</recipe>
<recipe SEGMENT="1">
<phase>0012</phase>
<parentOperation>0040</parentOperation>
<workcenter>COSTOHD1</workcenter>
</recipe>
</header>
</GSK_Canonical_MESGX2>
produces exactly the wanted, correct result:
HEADER#002001454979#0000617944
MANUOHD1
COSTOHD1
I have this xml:
<Artists>
<Name>Name1</Name>
<Name>Name2</Name>
<Name>Name3</Name>
<Name>Name4</Name>
<Name>Name5</Name>
...
<Name>Namex</Name>
</Artists>
I don't know how long the list is.
And I want to end up with something like:
<Limit_Artists>Name1; Name2; Name3; Name4; Name5; Name(n)</Limit_Artists>
But where the total length of must not exeed 127 chars and the last name must not "be split" in the middle. In other words I just need as many whole names from the top of the list, that fits within 127 chars.
I can put the names in a variable all together. but how can I stop before 127 chars?
best regards..
Not efficient but
<xsl:template match="Artists">
<Limit_Artists>
<xsl:value-of select="Name[string-length(string-join((preceding-sibling::Name, .), '')) le 127]" separator="; "/>
</Limit_Artists>
</xsl:template>
should do.
A complete example is
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:param name="limit" as="xs:integer" select="127"/>
<xsl:template match="Artists">
<Limit_Artists>
<xsl:value-of select="Name[string-length(string-join((preceding-sibling::Name, .), '')) le $limit]" separator="; "/>
</Limit_Artists>
</xsl:template>
</xsl:stylesheet>
Note that the code counts only the contents of Name elements but outputs them concatenated by ; so the output could that way be longer than 127. If you want to restrict the output to 127 characters then you have to change the string-join call to use
<xsl:template match="Artists">
<Limit_Artists>
<xsl:value-of select="Name[string-length(string-join((preceding-sibling::Name, .), '; ')) le 127]" separator="; "/>
</Limit_Artists>
</xsl:template>
respectively the full example to
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:param name="limit" as="xs:integer" select="127"/>
<xsl:template match="Artists">
<Limit_Artists>
<xsl:value-of select="Name[string-length(string-join((preceding-sibling::Name, .), '; ')) le $limit]" separator="; "/>
</Limit_Artists>
</xsl:template>
</xsl:stylesheet>
Or you could use sibling recursion along the following sibling axis, collecting the length of items until you hit the length you want to limit the output to. A complete example is
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:param name="limit" as="xs:integer" select="127"/>
<xsl:template match="Artists">
<Limit_Artists>
<xsl:apply-templates select="Name[1]">
<xsl:with-param name="limit" select="$limit"/>
</xsl:apply-templates>
</Limit_Artists>
</xsl:template>
<xsl:template match="Artists/Name">
<xsl:param name="limit" as="xs:integer"/>
<xsl:param name="length" as="xs:integer" select="0"/>
<xsl:variable name="new-length" select="$length + string-length()"/>
<xsl:if test="$new-length le $limit">
<xsl:value-of select="if ($length eq 0) then . else concat('; ', .)"/>
<xsl:apply-templates select="following-sibling::Name[1]">
<xsl:with-param name="limit" select="$limit"/>
<xsl:with-param name="length" select="$new-length"/>
</xsl:apply-templates>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
The above sample also only counts the Name characters but concatenates them so it would need to be adapted as well if you want to restrict the output to 127 characters. That could be done as follows:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:param name="limit" as="xs:integer" select="127"/>
<xsl:param name="sep" as="xs:string" select="'; '"/>
<xsl:template match="Artists">
<Limit_Artists>
<xsl:apply-templates select="Name[1]">
<xsl:with-param name="limit" select="$limit"/>
</xsl:apply-templates>
</Limit_Artists>
</xsl:template>
<xsl:template match="Artists/Name">
<xsl:param name="limit" as="xs:integer"/>
<xsl:param name="length" as="xs:integer" select="0"/>
<xsl:variable name="new-length" select="if ($length eq 0) then string-length() else $length + string-length($sep) + string-length()"/>
<xsl:if test="$new-length le $limit">
<xsl:value-of select="if ($length eq 0) then . else concat($sep, .)"/>
<xsl:apply-templates select="following-sibling::Name[1]">
<xsl:with-param name="limit" select="$limit"/>
<xsl:with-param name="length" select="$new-length"/>
</xsl:apply-templates>
</xsl:if>
</xsl:template>
</xsl:stylesheet>