using xsl to create new nodes and elements xml - html

I need an XSL solution to replace XML nodes with new nodes.
Say I have the following existing XML structure:
<?xml version="1.0" encoding="UTF-8"?>
<ns0:MT_AvanzarEventoIdCase2_Req_Out xmlns:ns0="http://colpensiones.gov.co/AvanzarEventoIdCase2">
<configuracion>
<tipoSistemaExterno>test4</tipoSistemaExterno>
<tipoProcesamiento>test5</tipoProcesamiento>
<idCorrelacion>test6</idCorrelacion>
</configuracion>
<informacionEventoCasoBPM>
<numeroRadicadoCaso>test</numeroRadicadoCaso>
<nombreEvento>test2</nombreEvento>
<informacionRelacionada>test3</informacionRelacionada>
</informacionEventoCasoBPM>
</ns0:MT_AvanzarEventoIdCase2_Req_Out>
and I need to tranform to this structure:
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:per="http://www.colpensiones.gov.co/contracts/1.0/personas"
xmlns:per1="http://www.colpensiones.gov.co/schemas/1.0/personas"
xmlns:com="http://www.colpensiones.gov.co/contracts/1.0/comun"
xmlns:com1="http://www.colpensiones.gov.co/schemas/1.0/comun">
<soapenv:Header>
<per:Configuracion>
<per1:tipoSistemaExterno>?</per1:tipoSistemaExterno>
<per1:tipoProcesamiento>?</per1:tipoProcesamiento>
<per1:idCorrelacion>?</per1:idCorrelacion>
</per:Configuracion>
</soapenv:Header>
<soapenv:Body>
<com:InformacionEventoCasoBPM>
<com1:numeroRadicadoCaso>?</com1:numeroRadicadoCaso>
<com1:nombreEvento>?</com1:nombreEvento>
<com1:informacionRelacionada>?</com1:informacionRelacionada>
</com:InformacionEventoCasoBPM>
</soapenv:Body>
</soapenv:Envelope>
I'he been trying for 1 week and I couldn't, This was my structure but it didn't work:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:per="http://www.colpensiones.gov.co/contracts/1.0/personas"
xmlns:per1="http://www.colpensiones.gov.co/schemas/1.0/personas"
xmlns:com="http://www.colpensiones.gov.co/contracts/1.0/comun"
xmlns:com1="http://www.colpensiones.gov.co/schemas/1.0/comun"
exclude-result-prefixes="soapenv per per1 com com1">
<xsl:template match = "/">
<soapenv:envelope>
<soapenv:header>
<per:Configuracion>
<per1:tipoSistemaExterno><xsl:value-of select = "tipoSistemaExterno"/></per1:tipoSistemaExterno>
<per1:tipoProcesamiento><xsl:value-of select = "tipoProcesamiento"/></per1:tipoProcesamiento>
<per1:idCorrelacion><xsl:value-of select = "idCorrelacion"/></per1:idCorrelacion>
</per:Configuracion>
</soapenv:header>
<soapenv:body>
<com:InformacionEventoCasoBPM>
<com1:numeroRadicadoCaso><xsl:value-of select = "numeroRadicadoCaso"/></com1:numeroRadicadoCaso>
<com1:nombreEvento><xsl:value-of select = "nombreEvento"/></com1:nombreEvento>
<com1:informacionRelacionada><xsl:value-of select = "informacionRelacionada"/></com1:informacionRelacionada>
</com:InformacionEventoCasoBPM>
</soapenv:body>
</soapenv:envelope>
</xsl:template>
</xsl:stylesheet>
Thank for your help.

I just assumed that you want exactly that output. The code for that would be:
<xsl:template match="/">
<xsl:element name="soapenv-Envelope">
<xsl:element name="soapenv-Header">
<xsl:apply-templates select="//configuracion"/>
</xsl:element>
<xsl:element name="soapenv-Body">
<xsl:apply-templates select="//informacionEventoCasoBPM"/>
</xsl:element>
</xsl:element>
</xsl:template>
<xsl:template match="configuracion">
<xsl:element name="per-Configuration">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="*[ancestor::configuracion]">
<xsl:element name="{concat('per1-', local-name())}">
<!-- copy the text within the node -->
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="informacionEventoCasoBPM">
<xsl:element name="com-InformacionEventoCasoBPM">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="*[ancestor::informacionEventoCasoBPM]">
<xsl:element name="{concat('com1-', local-name())}">
<!-- copy the text within the node -->
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
I replaced the : with - though because I did not want to declare new namespaces.

Related

Handle excluded element in a foreach

In first template, I am intentionally excluding an element ('milk') because the parsed data map is relatively flat and I would like to use XSLT to categorize and structure the data. The aim is to process the excluded element ('milk') in the second template. The both templates works running them one at a time. Running the templates together will not show the result of the excluded element ('milk') which should set another attribute name and attribute value.
JSON:
<data>
{
"storage": {
"pencils": 12,
"milk": 8,
"rulers": 4
}
}
</data>
XSL:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform
version="3.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:storage="http://www.exammple.com/1"
xmlns:office="http://www.exammple.com/2"
xmlns:item="http://www.exammple.com/3"
expand-text="yes">
<xsl:output method="xml" indent="yes"/>
<xsl:mode on-no-match="shallow-skip"/>
<!-- Parse JSON to XML -->
<xsl:template match="data">
<storage:one>
<xsl:apply-templates select="json-to-xml(.)"/>
</storage:one>
</xsl:template>
<!-- Print map -->
<!-- <xsl:template match="*[#key = 'storage']"> <xsl:copy-of select=".."/> </xsl:template> -->
<xsl:template match="*[#key='storage']">
<xsl:for-each select="*[not(#key='milk')]">
<xsl:element name="item:{#key}">
<xsl:attribute name="office">plant-1</xsl:attribute>
<xsl:value-of select="text()"/>
</xsl:element>
</xsl:for-each>
</xsl:template>
<xsl:template match="*[#key='milk']">
<xsl:for-each select=".">
<xsl:element name="item:{#key}">
<xsl:attribute name="beverage">plant-2</xsl:attribute>
<xsl:value-of select="text()"/>
</xsl:element>
</xsl:for-each>
</xsl:template>
</xsl:transform>
Result:
<?xml version="1.0" encoding="UTF-8"?>
<storage:one xmlns:item="http://www.exammple.com/3"
xmlns:office="http://www.exammple.com/2"
xmlns:storage="http://www.exammple.com/1">
<item:pencils office="plant-1">12</item:pencils>
<item:rulers office="plant-1">4</item:rulers>
</storage:one>
Wanted result:
<?xml version="1.0" encoding="UTF-8"?>
<storage:one xmlns:item="http://www.exammple.com/3"
xmlns:office="http://www.exammple.com/2"
xmlns:storage="http://www.exammple.com/1">
<item:pencils office="plant-1">12</item:pencils>
<item:rulers office="plant-1">4</item:rulers>
<item:milk beverage="plant-2">8</item:milk>
</storage:one>
Your second template is never matched, because it is never reached. All elements are processed by <xsl:template match="*[#key='storage']"> - which doesn't have an <xsl:apply-templates ...> to reach further templates.
Your first template does not recurse into its children. So add an <xsl:apply-templates select="*" /> to the end of the first template:
<xsl:template match="*[#key='storage']">
<xsl:for-each select="*[not(#key='milk')]">
<xsl:element name="item:{#key}">
<xsl:attribute name="office">plant-1</xsl:attribute>
<xsl:value-of select="text()"/>
</xsl:element>
</xsl:for-each>
<xsl:apply-templates select="*" />
</xsl:template>
This will try to apply further templates at the level of "storage" and therefore match the second template.
I would write templates for each different output type and if the order of the output is different from the order of the input throw in an xsl:sort or an XPath 3.1 sort call to change the order:
<xsl:template match="data">
<storage:one>
<xsl:apply-templates select="json-to-xml(.)"/>
</storage:one>
</xsl:template>
<xsl:template match="*[#key = 'storage']">
<xsl:apply-templates select="sort(*, (), function($el) { $el/#key = 'milk' })"/>
</xsl:template>
<xsl:template match="*[#key='storage']/*[not(#key='milk')]">
<xsl:element name="item:{#key}">
<xsl:attribute name="office">plant-1</xsl:attribute>
<xsl:value-of select="text()"/>
</xsl:element>
</xsl:template>
<xsl:template match="*[#key='storage']/*[#key='milk']">
<xsl:element name="item:{#key}">
<xsl:attribute name="beverage">plant-2</xsl:attribute>
<xsl:value-of select="text()"/>
</xsl:element>
</xsl:template>

Datatype map: Query array values using "for-each"

I am looking to extract values from an array where each array is connected to a object key name.
The problem I encounter is not knowing how to structure the inner "xsl:foreach" toward a map array.
I will later differentiate the elements by adding attributes but I left that out to keep the question and data at minimal level.
JSON:
<data>
{
"datasheets": {
"balance": {
"cash": [4, 2, 3, 1],
"bank": [5, 8, 7, 9]
}
}
}
</data>
XSL:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:docroot="http://www.example.org/1"
xmlns:report="http://www.example.org/2"
xmlns:cells="http://www.example.org/3"
expand-text="yes"
>
<xsl:output method="xml" indent="yes"/>
<xsl:mode on-no-match="shallow-skip"/>
<!-- Parse JSON to XML -->
<xsl:template match="data">
<docroot>
<xsl:apply-templates select="json-to-xml(.)/*"/>
</docroot>
</xsl:template>
<!-- Transform balance data -->
<xsl:template match="*[#key = 'balance']">
<report:yearly-values>
<xsl:for-each select="./*">
<!-- <xsl:for-each select="./*"> -->
<xsl:element name="cells:{#key}">Placeholder</xsl:element>
<!-- </xsl:for-each> -->
</xsl:for-each>
</report:yearly-values>
</xsl:template>
</xsl:transform>
Result:
<?xml version="1.0" encoding="UTF-8"?>
<docroot xmlns:cells="http://www.example.org/3"
xmlns:docroot="http://www.example.org/1"
xmlns:report="http://www.example.org/2">
<report:yearly-values>
<cells:cash>Placeholder</cells:cash>
<cells:bank>Placeholder</cells:bank>
</report:yearly-values>
</docroot>
Wanted result:
<?xml version="1.0" encoding="UTF-8"?>
<docroot xmlns:cells="http://www.example.org/3"
xmlns:docroot="http://www.example.org/1"
xmlns:report="http://www.example.org/2">
<report:yearly-values>
<cells:cash>4</cells:cash>
<cells:cash>2</cells:cash>
<cells:cash>3</cells:cash>
<cells:cash>1</cells:cash>
<cells:bank>5</cells:bank>
<cells:bank>8</cells:bank>
<cells:bank>7</cells:bank>
<cells:bank>9</cells:bank>
</report:yearly-values>
</docroot>
When you first take this debugging step to see what is going on:
<xsl:template match="*[#key = 'balance']">
<report:yearly-values>
<xsl:copy-of select="."/>
</report:yearly-values>
</xsl:template>
Would give this xml-fragment:
<report:yearly-values>
<map xmlns="http://www.w3.org/2005/xpath-functions" key="balance">
<array key="cash">
<number>4</number>
<number>2</number>
<number>3</number>
<number>1</number>
</array>
<array key="bank">
<number>5</number>
<number>8</number>
<number>7</number>
<number>9</number>
</array>
</map>
</report:yearly-values>
Then it is more clear what you need. Take the for-each one level deeper and use the #key of the parent for you element-name, like this:
<xsl:template match="*[#key = 'balance']">
<report:yearly-values>
<xsl:for-each select="*/*">
<xsl:element name="cells:{parent::*/#key}"><xsl:value-of select="text()"/></xsl:element>
</xsl:for-each>
</report:yearly-values>
</xsl:template>
You're just iterating over the two arrays but not the content of the arrays. The following will produce the wanted output:
<xsl:for-each select="./*/*">
<!-- <xsl:for-each select="./*/*"> -->
<xsl:element name="cells:{parent::*/#key}">
<xsl:value-of select="."/>
</xsl:element>
<!-- </xsl:for-each> -->
</xsl:for-each>

Converting an RSS pubDate to a mySQL time stamp format using XSLT

I've got a little tool which strips out and re-arranges an iTunes formatted RSS feed and converts it to a nice simple XML file.
I then import the cleansed XML into mySQL to do things with later.
I need to be able to convert the pubDate in the feed to a mySQL timestamp so I can import this properly into a TIMESTAMP field in my table.
I'm having some issues with it.
My current XSL file does a tidy up on the date, but I don't need this at all.
I just want the <pubDate> node to have the correct mySQL friendly timestamp inside instead.
I've not yet managed to find anything which does what I need. Any pointers?
Here is my XSLT file...
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:cc="http://web.resource.org/cc/"
xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
xmlns:libsyn="http://libsyn.com/rss-extension"
xmlns:media="http://search.yahoo.com/mrss/"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
exclude-result-prefixes="atom cc itunes libsyn media rdf">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<data>
<entries>
<xsl:apply-templates select="rss/channel/item"></xsl:apply-templates>
</entries>
</data>
</xsl:template>
<xsl:template match="item">
<entry>
<title><xsl:value-of select="title"/></title>
<link><xsl:value-of select="link"/></link>
<description><xsl:value-of select="description" disable-output-escaping="yes"/></description>
<subtitle><xsl:value-of select="itunes:subtitle"/></subtitle>
<pubDate><xsl:value-of select="pubDate"/></pubDate>
<xsl:apply-templates select="pubDate"/>
<explicit><xsl:value-of select="itunes:explicit"/></explicit>
<podcastImage><xsl:value-of select="itunes:image/#href"/></podcastImage>
<podcastURL><xsl:value-of select="enclosure/#url"/></podcastURL>
<podcastLength><xsl:value-of select="enclosure/#length"/></podcastLength>
<podcastDuration><xsl:value-of select="itunes:duration"/></podcastDuration>
</entry>
</xsl:template>
<xsl:template match="pubDate">
<date>
<xsl:attribute name="time"><xsl:value-of select="substring(text(),18,5)"/></xsl:attribute>
<xsl:call-template name="format-from-rfc-to-iso">
<xsl:with-param name="rfc-date" select="text()"/>
</xsl:call-template>
</date>
</xsl:template>
<xsl:template name="format-from-rfc-to-iso">
<xsl:param name="rfc-date"/>
<xsl:param name="day-with-zero" select="format-number(substring(substring($rfc-date,6,11),1,2),'00')"/>
<xsl:param name="month-with-zero">
<xsl:if test="contains($rfc-date,'Jan')">01</xsl:if>
<xsl:if test="contains($rfc-date,'Feb')">02</xsl:if>
<xsl:if test="contains($rfc-date,'Mar')">03</xsl:if>
<xsl:if test="contains($rfc-date,'Apr')">04</xsl:if>
<xsl:if test="contains($rfc-date,'May')">05</xsl:if>
<xsl:if test="contains($rfc-date,'Jun')">06</xsl:if>
<xsl:if test="contains($rfc-date,'Jul')">07</xsl:if>
<xsl:if test="contains($rfc-date,'Aug')">08</xsl:if>
<xsl:if test="contains($rfc-date,'Sep')">09</xsl:if>
<xsl:if test="contains($rfc-date,'Oct')">10</xsl:if>
<xsl:if test="contains($rfc-date,'Nov')">11</xsl:if>
<xsl:if test="contains($rfc-date,'Dec')">12</xsl:if>
</xsl:param>
<xsl:param name="year-full" select="format-number(substring(substring($rfc-date,6,11),7,5),'####')"/>
<xsl:param name="rfc-date-to-iso" select="concat($year-full,'-',$month-with-zero,'-',$day-with-zero)"/>
<xsl:value-of select="$rfc-date-to-iso"/>
</xsl:template>
</xsl:stylesheet>
The current date/time looks like this from the rss feed:
<pubDate>Sun, 07 Feb 2016 00:00:56 -0500</pubDate>
I'd like it to by displayed like this so it can be inserted into mySQL:
<pubDate>2016-02-07 00:00:56</pubDate>
I use PHP to process this.
$xml = new DOMDocument;
$xml->load('podbean.xml');
$xsl = new DOMDocument;
$xsl->load('podbean.xsl');
// Configure the transformer
$proc = new XSLTProcessor;
$proc->importStyleSheet($xsl); // attach the xsl rules
$proc->transformToXML($xml);
$proc->transformToURI($xml,'itunes.xml');
Simon
Using a processor that supports the EXSLT str:tokenize() function (as libxslt does), you can do something like this:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:str="http://exslt.org/strings"
extension-element-prefixes="str">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- ... -->
<xsl:template match="item">
<entry>
<!-- ... -->
<pubDate>
<xsl:variable name="date-tokens" select="str:tokenize(pubDate, ' ' )" />
<!-- year -->
<xsl:value-of select="$date-tokens[4]" />
<xsl:text>-</xsl:text>
<!-- month -->
<xsl:variable name="mmm" select="$date-tokens[3]" />
<xsl:variable name="m" select="string-length(substring-before('JanFebMarAprMayJunJulAugSepOctNovDec', $mmm)) div 3 + 1" />
<xsl:value-of select="format-number($m, '00')" />
<xsl:text>-</xsl:text>
<!-- day -->
<xsl:value-of select="format-number($date-tokens[2], '00')" />
<xsl:text> </xsl:text>
<!-- time -->
<xsl:value-of select="$date-tokens[5]" />
</pubDate>
<!-- ... -->
</entry>
</xsl:template>
</xsl:stylesheet>

Adding namespaces to elements only and changing to uppercase

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>

How to call template with name as a variable in XSLT?

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.