get the xml attribute value using xslt tree wise - xslt

This is my xml file:
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="try.xsl"?>
<oneday>
<team1 id="1" team="India">
<team2 id="2" team="gujarat">
<team3 id="3" team="guj11"></team3>
</team2>
</team1>
</oneday>
This is my xsl file:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:output method="text" />
<xsl:template match="*">
<xsl:value-of select="local-name()"/>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="text()[normalize-space(.)]">
<xsl:value-of select="concat(':', .)"/>
</xsl:template>
</xsl:stylesheet>
This is my output:
oneday
team1
team2
team3
But I want to output something like this:
oneday
team1:India
team2:Gujarat
team3:Guj11

How's this:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />
<xsl:template match="*">
<xsl:apply-templates select="ancestor::*" mode="spacing" />
<xsl:value-of select="local-name()"/>
<xsl:if test="#team">
<xsl:value-of select="concat(':', #team)"/>
</xsl:if>
<xsl:text>
</xsl:text>
<xsl:apply-templates select="*" />
</xsl:template>
<xsl:template match="*" mode="spacing">
<xsl:text> </xsl:text>
</xsl:template>
</xsl:stylesheet>
When run on your sample XML, this produces:
oneday
team1:India
team2:gujarat
team3:guj11
When run on a slightly more complex XML:
<oneday>
<team1 id="1" team="India">
<team2 id="2" team="gujarat">
<team3 id="3" team="guj11"></team3>
</team2>
<team6 team="Mumbai" />
</team1>
<team4 team="France">
<team5 team="Paris" />
</team4>
</oneday>
It produces:
oneday
team1:India
team2:gujarat
team3:guj11
team6:Mumbai
team4:France
team5:Paris

Related

Generate new group based on node value in XSLT

I am new to XSLT, and I am trying to create new group based on node value eventType so if eventType is alert, create new group event.
I am checking for last sibling
Input XML
<?xml version="1.0" encoding="UTF-8"?><Rowsets >
<Row>
<eventId>2</eventId>
<plantId>1020</plantId>
<workCenter>WC1</workCenter>
<eventType>alert</eventType>
<eventText>Downtime</eventText>
<eventDesc>WorkcenterDown</eventDesc>
</Row>
<Row>
<eventId>3</eventId>
<plantId>1021</plantId>
<workCenter>WC1</workCenter>
<eventType>alert</eventType>
<eventText>Downtime</eventText>
<eventDesc>WorkcenterDown</eventDesc>
</Row>
<Row>
<eventId>4</eventId>
<plantId>1020</plantId>
<workCenter>WC2</workCenter>
<eventType>incident</eventType>
<eventText>eventtext</eventText>
<eventDesc>failed</eventDesc>
</Row>
<Row>
<plantId>1020</plantId>
<workCenter>WC2</workCenter>
<eventType>incident</eventType>
<eventText>Text</eventText>
<eventDesc>failed</eventDesc>
</Row>
</Rowsets>
Expected output:
<?xml version="1.0" encoding="UTF-8"?>
<Rowsets>
<Alert>
<element>
<Title>Downtime:DIA01</Title>
<eventDesc>WorkcenterDown</eventDesc>
</element>
<element>
<Title>Downtime:DIA01</Title>
<eventDesc>WorkcenterDown</eventDesc>
</element>
</Alert>
<Incident>
<element>
<Title>YAT < 60%:DIA01</Title>
<eventDesc>7 Parts in 60 minutes have failed</eventDesc>
</element>
<element>
<Title>YAT < 60%:DIA01</Title>
<eventDesc>7 Parts in 60 minutes have failed</eventDesc>
</element>
</Incident>
</Rowsets>
Based on eventType, I want to generate group.
I am using this XSLT:
<?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="/">
<Rowsets>
<Rowset>
<xsl:variable name="Type" select="'alert'"/>
<xsl:for-each select="/Rowsets/Rowset/Row">
<xsl:choose>
<xsl:when test="$Type = eventType">
<element>
<xsl:variable name="text" select="eventText"/>
<xsl:variable name="WC" select="workCenter"/>
<Title><xsl:value-of select="concat($text,':',$WC)" /></Title>
<xsl:copy-of select="eventDesc"/>
</element>
</xsl:when>
<xsl:otherwise>
<element>
<xsl:variable name="text" select="eventText"/>
<xsl:variable name="WC" select="workCenter"/>
<Title><xsl:value-of select="concat($text,':',$WC)" /></Title>
<xsl:copy-of select="eventDesc"/>
</element>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</Rowset>
</Rowsets>
</xsl:template>
</xsl:stylesheet>
Need help in generating id and key based on eventType
This is a grouping problem - and a rather trivial one at that. In XSLT 2.0 you could do simply:
XSLT 2.0
<xsl:stylesheet version="2.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="Rowsets">
<Rowsets>
<xsl:for-each-group select="Row" group-by="eventType">
<xsl:element name="{current-grouping-key()}">
<xsl:for-each select="current-group()">
<element>
<Title>
<xsl:value-of select="eventText, workCenter" separator=":"/>
</Title>
<xsl:copy-of select="eventDesc"/>
</element>
</xsl:for-each>
</xsl:element>
</xsl:for-each-group>
</Rowsets>
</xsl:template>
</xsl:stylesheet>
Alternatively, with only two possible types, you could do:
XSLT 1.0
<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="Rowsets">
<Rowsets>
<Alert>
<xsl:apply-templates select="Row[eventType='alert']"/>
</Alert>
<Incident>
<xsl:apply-templates select="Row[eventType='incident']"/>
</Incident>
</Rowsets>
</xsl:template>
<xsl:template match="Row">
<element>
<Title>
<xsl:value-of select="eventText"/>
<xsl:text>:</xsl:text>
<xsl:value-of select="workCenter"/>
</Title>
<xsl:copy-of select="eventDesc"/>
</element>
</xsl:template>
</xsl:stylesheet>
This is assuming you don't mind creating a group even if it is empty. Otherwise you would do:
<xsl:template match="Rowsets">
<Rowsets>
<xsl:variable name="alerts" select="Row[eventType='alert']"/>
<xsl:variable name="incidents" select="Row[eventType='incident']"/>
<xsl:if test="$alerts">
<Alert>
<xsl:apply-templates select="Row[eventType='alert']"/>
</Alert>
</xsl:if>
<xsl:if test="$incidents">
<Incident>
<xsl:apply-templates select="Row[eventType='incident']"/>
</Incident>
</xsl:if>
</Rowsets>
</xsl:template>
P.S. Note that XML is case-sensitive: <Alert> is not the same as <alert>.

Facing Issue in XSLT Format

I am looking my xslt in below format:
<xml>
<apis>
<name>API Name</name>
<comment> Comment</comment>
<version>12</version>
</apis>
</xml>
XSLT Code:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:L7j="http://ns.l7tech.com/2012/08/jdbc-query-result" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:template match="/">
<xml>
<xsl:apply-templates select="//L7j:col" />
</xml>
</xsl:template>
<xsl:template match="//L7j:col">
<api>
<xsl:element name="{#name}">
<xsl:value-of select="." /></xsl:element>
</api>
</xsl:template>
</xsl:stylesheet>
Input XML:
<?xml version="1.0" encoding="UTF-8"?>
<L7j:jdbcQueryResult xmlns:L7j="http://ns.l7tech.com/2012/08/jdbc-query-result">
<L7j:row>
<L7j:col name="name" type="java.lang.String">Policy for service #0b8bab6913cc588557b6973e94d1bfdd, WSTrustSoapService</L7j:col>
<L7j:col name="comment">
<![CDATA[NULL]]>
</L7j:col>
<L7j:col name="version" type="java.lang.Integer">18</L7j:col>
</L7j:row>
<L7j:row>
<L7j:col name="name" type="java.lang.String">Policy for service #0b8bab6913cc588557b6973e94d5893d, UUPRStub</L7j:col>
<L7j:col name="comment">
<![CDATA[NULL]]>
</L7j:col>
<L7j:col name="version" type="java.lang.Integer">16</L7j:col>
</L7j:row>
</L7j:jdbcQueryResult>
If I understand correctly, you want to do:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:L7j="http://ns.l7tech.com/2012/08/jdbc-query-result"
exclude-result-prefixes="L7j">
<xsl:output method="xml" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="/L7j:jdbcQueryResult">
<xml>
<xsl:apply-templates/>
</xml>
</xsl:template>
<xsl:template match="L7j:row">
<apis>
<xsl:apply-templates/>
</apis>
</xsl:template>
<xsl:template match="L7j:col">
<xsl:element name="{#name}">
<xsl:value-of select="." />
</xsl:element>
</xsl:template>
</xsl:stylesheet>

XSLT 2.0 XPATH expression with variable

I'm working on a Java based xsl-transformation (XSLT 2.0, could also be XSLT 3.0 if there is a free processor for java) with different input xml files. one input file could look like this:
<?xml version="1.0" encoding="UTF-8"?>
<TEST>
<MyElement>
<CHILD>A</CHILD>
<CHILDBEZ>ABEZ</CHILDBEZ>
<NotInteresting></NotInteresting>
</MyElement>
<MyElement>
<CHILD>B</CHILD>
<CHILDBEZ>BBEZ</CHILDBEZ>
<NotInteresting2></NotInteresting2>
</MyElement>
</TEST>
I want to copy all elements but "NotInteresting" and rename the two nodes CHILD and CHILDBEZ based on two parameters that I get from a mapping file:
the xpath expression that tells me where the text of interest is placed (in this case: TEST/MyFirstElement/CHILD and TEST/MyFirstElement/CHILDBEZ)
and the names of the elements what they should have in the output file (in this case: childName and childBez)
the mapping file:
<?xml version="1.0" encoding="UTF-8"?>
<element root="TEST">
<childName>TEST/MyElement/CHILD</childName>
<childBez>TEST/MyElement/CHILDBEZ</childBez>
</element>
desired output:
<TEST>
<MyElement>
<childName>A</childName>
<childBez>ABEZ</childBez>
</MyElement>
<MyElement>
<childName>B</childName>
<childBez>BBEZ</childBez>
</MyElement>
</TEST>
what I have so far:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="2.0 "
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" xmlns="http://www.apoverlag.at"
xmlns:apo="http://www.apoverlag.at">
<xsl:variable name="vars" select="document('mapping.xml')"/>
<xsl:param name="src" />
<xsl:variable name="path" xpath-default-namespace="" select="$src/path"/> <!-- = TEST/*-->
<xsl:template match="/">
<xsl:for-each select="$path">
<xsl:call-template name="buildNode">
<xsl:with-param name="currentNode" select="current()"></xsl:with-param>
</xsl:call-template>
</xsl:for-each>
</xsl:template>
<xsl:template name="buildNode">
<xsl:param name="currentNode" />
<xsl:element name="test">
<xsl:for-each select="$vars/element/#root">
<xsl:for-each select="$vars/element/*">
<xsl:element name="{name(.)}"> <xsl:value-of select="concat($currentNode,'/',current())" />
</xsl:element>
</xsl:for-each>
</xsl:for-each>
</xsl:element>
</xsl:template>
</xsl:transform>
My problem is that:
<xsl:value-of select="concat($currentNode,'/',current())" />
gives me "/TEST/MyFirstElement/CHILD" when I try it hardcoded with:
<xsl:value-of select="$currentNode/CHILD" />
I receive my desired output. Can anyone give me a hint how to solve this problem?
I would suggest a radically different approach. To simplify, I have used a mapping document with full paths (starting with the / root node):
mapping xml
<element root="TEST">
<childName>/TEST/MyElement/CHILD</childName>
<childBez>/TEST/MyElement/CHILDBEZ</childBez>
</element>
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="mapping" select="document('mapping.xml')"/>
<xsl:key name="map" match="*" use="." />
<xsl:template match="/">
<xsl:variable name="first-pass">
<xsl:apply-templates mode="first-pass"/>
</xsl:variable>
<xsl:apply-templates select="$first-pass/*"/>
</xsl:template>
<xsl:template match="*" mode="first-pass">
<xsl:param name="parent-path"/>
<xsl:variable name="path" select="concat($parent-path, '/', name())" />
<xsl:variable name="replacement" select="key('map', $path, $mapping)" />
<xsl:element name="{if ($replacement) then name($replacement) else name()}">
<xsl:attribute name="original" select="not($replacement)"/>
<xsl:apply-templates mode="first-pass">
<xsl:with-param name="parent-path" select="$path"/>
</xsl:apply-templates>
</xsl:element>
</xsl:template>
<xsl:template match="*">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[#original='true' and not(descendant::*/#original='false')]"/>
</xsl:stylesheet>
Result, when applied to the provided input:
<?xml version="1.0" encoding="UTF-8"?>
<TEST>
<MyElement>
<childName>A</childName>
<childBez>ABEZ</childBez>
</MyElement>
<MyElement>
<childName>B</childName>
<childBez>BBEZ</childBez>
</MyElement>
</TEST>

XSLT generating attributes if source-Element is in parameterfile

i got an xml-file with some elements. For some of these is an aqvivalent in a parameter xml-file along with some other elements.
I want to add these other elements from parm-file as parameter to output file if element-names are matching. (the Attributes should only be generated if an element "InvoiceHeader" exists in the source-xml.
Here is my code...
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:variable name="rpl" select="document('ParamInvoice.xml')"></xsl:variable>
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<xsl:apply-templates></xsl:apply-templates>
</xsl:template>
<xsl:template match="*">
<xsl:copy>
<xsl:if test="$rpl/StoraInvoice/local-name()">
<xsl:call-template name="AttributeErzeugen">
<xsl:with-param name="attr" select="$rpl/StoraInvoice/local-name()"></xsl:with-param>
</xsl:call-template>
</xsl:if>
<xsl:apply-templates></xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template name="AttributeErzeugen">
<xsl:param name="attr"></xsl:param>
<xsl:for-each select="$attr">
<xsl:attribute name="{Attibute/#name}"><xsl:value-of select="."></xsl:value- of></xsl:attribute>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
and here the param-file
<?xml version="1.0" encoding="UTF-8"?>
<StoraInvoice>
<InvoiceHeader>
<Attribute name="Fuehrend">YYY</Attribute>
<Attribute name="Feld">FFFF</Attribute>
<Attribute name="Format">XYZXYZ</Attribute>
</InvoiceHeader>
</StoraInvoice>
Siegfried
This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="my:my"
exclude-result-prefixes="my">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<my:rpl>
<StoraInvoice>
<t>
<InvoiceHeader>
<Attribute name="Fuehrend">YYY</Attribute>
<Attribute name="Feld">FFFF</Attribute>
<Attribute name="Format">XYZXYZ</Attribute>
</InvoiceHeader>
</t>
</StoraInvoice>
</my:rpl>
<xsl:variable name="rpl" select="document('')/*/my:rpl"/>
<xsl:template match="*">
<xsl:variable name="vInvoiceElement" select=
"$rpl/StoraInvoice/*[name()=name(current())]"/>
<xsl:copy>
<xsl:if test="$vInvoiceElement">
<xsl:call-template name="AttributeErzeugen">
<xsl:with-param name="pInvoiced" select="$vInvoiceElement"/>
</xsl:call-template>
</xsl:if>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template name="AttributeErzeugen">
<xsl:param name="pInvoiced"/>
<xsl:for-each select="$pInvoiced/InvoiceHeader/Attribute">
<xsl:attribute name="{#name}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
when applied on this XML document:
<t/>
produces the wanted, correct result:
<t Fuehrend="YYY" Feld="FFFF" Format="XYZXYZ"/>

getting attribute as column headers

I have the following XML:
<DEVICEMESSAGES>
<VERSION xml="1" checksum="" revision="0" envision="33050000" device="" />
<HEADER id1="0001" id2="0001" content="Nasher[<messageid>]: <!payload>" />
<MESSAGE level="7" parse="1" parsedefvalue="1" tableid="15" id1="24682" id2="24682" eventcategory="1003010000" content="Access to <webpage> was blocked due to its category (<info> by <hostname>)" />
</DEVICEMESSAGES>
I am using the following XSLT:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="DEVICEMESSAGES/HEADERS">
<xsl:value-of select="#id2"/>,<xsl:text/>
<xsl:value-of select="#content"/>,<xsl:text/>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
I get the following output:
0001 , Nasher[<messageid>]: <!payload>
whereas I need the column headings, too:
id2, content
0001 , Nasher[<messageid>]: <!payload>
If DEVICEMESSAGES is the document element and you have repeating MESSAGE elements, then this should work:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="DEVICEMESSAGES">
<xsl:text>id2,content,
</xsl:text>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="DEVICEMESSAGES/HEADER">
<xsl:value-of select="#id2"/>,<xsl:text/>
<xsl:value-of select="#content"/>,<xsl:text/>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
If you have a different document element, then adjust the template to match on that.
For instance, if the document element is doc and you had 1 to N number of DEVICEMESSAGES elements:
<doc>
<DEVICEMESSAGES>
<VERSION xml="1" checksum="" revision="0" envision="33050000" device="" />
<HEADER id1="0001" id2="0001" content="Nasher[<messageid>]: <!payload>" />
<MESSAGE level="7" parse="1" parsedefvalue="1" tableid="15" id1="24682" id2="24682" eventcategory="1003010000" content="Access to <webpage> was blocked due to its category (<info> by <hostname>)" />
</DEVICEMESSAGES>
<DEVICEMESSAGES>
<VERSION xml="1" checksum="" revision="0" envision="33050000" device="" />
<HEADER id1="0002" id2="0002" content="Nasher[<messageid>]: <!payload>" />
<MESSAGE level="7" parse="1" parsedefvalue="1" tableid="15" id1="24682" id2="24682" eventcategory="1003010000" content="Access to <webpage> was blocked due to its category (<info> by <hostname>)" />
</DEVICEMESSAGES>
</doc>
then you could use this:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="doc">
<xsl:text>id2,content,
</xsl:text>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="DEVICEMESSAGES/HEADER">
<xsl:value-of select="#id2"/>,<xsl:text/>
<xsl:value-of select="#content"/>,<xsl:text/>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
EDIT: Another alternative that uses the template match of the root node and does not need to know what the document element is:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:text>id2,content,
</xsl:text>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="DEVICEMESSAGES/HEADER">
<xsl:value-of select="#id2"/>,<xsl:text/>
<xsl:value-of select="#content"/>,<xsl:text/>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>