Reputation: 21
I have a xml and want some desired output, where element xpath is calculated and added into an attribute called elementXpath. That is done.
Now what I want is to get attributes xpath as well and that xpath should come under attribute value.
<?xml version="1.0" encoding="UTF-8"?>
<test>
<request function="createNewJob" style="11" responseType="labelURL"></request>
</test>
and my xslt
<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:template match="*">
<xsl:param name="path"/>
<xsl:variable name="my-path">
<xsl:for-each select="ancestor-or-self::*">
<xsl:value-of select="concat('/',name())"/>
<xsl:if test="(preceding-sibling::*|following-sibling::*)[name()=name(current())]">
<xsl:value-of select="concat('[',count(preceding-sibling::*[name()=name(current())])+1,']')"/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:copy>
<xsl:variable name="elementXpath" select="replace($my-path, '/.*?:|/.*?','/*:')"/>
<xsl:attribute name="xpath">
<xsl:value-of select="concat($elementXpath,'/text()')"/>
</xsl:attribute>
<xsl:copy-of select="@*"/>
<xsl:for-each select="@*">
<xsl:variable name="attr" select="concat($elementXpath,'/@',name())" />
<xsl:value-of select="$attr"/>
<xsl:text>,
</xsl:text>
</xsl:for-each>
<xsl:apply-templates>
<xsl:with-param name="path" select="$my-path"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
Current Output
<?xml version="1.0" encoding="UTF-8"?>
<test xpath="/*:test/text()">
<request xpath="/*:test/*:request/text()"
function="createNewJob"
style="11"
responseType="labelURL">/*:test/*:request/@function,
/*:test/*:request/@style,
/*:test/*:request/@responseType,
</request>
</test>
Desired Output:
<?xml version="1.0" encoding="UTF-8"?>
<test xpath="/*:test/text()">
<request xpath="/*:test/*:request/text()"
function="/*:test/*:request/@function"
style="/*:test/*:request/@style"
responseType="/*:test/*:request/@responseType">
</request>
</test>
Another Sample:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns:processShipmentResponse xmlns:ns="http://ws.business.uss.transforce.ca">
<ns:return xmlns:ax27="http://dto.uss.transforce.ca/xsd"
xmlns:ax25="http://ws.business.uss.transforce.ca/xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ax25:error xsi:nil="true"/>
<ax25:processShipmentResult>
<ax27:shipment someDummyAttribute="dummyAttributeValue">
<ax27:transit_time color="blue">1</ax27:transit_time>
<ax27:request id="1" function="createNewJob" style="11" responseType="labelURL"></ax27:request>
<ax27:transit_time color="red">1</ax27:transit_time>
<ax27:transit_time_guaranteed>false</ax27:transit_time_guaranteed>
</ax27:shipment>
</ax25:processShipmentResult>
</ns:return>
</ns:processShipmentResponse>
</soapenv:Body>
</soapenv:Envelope>
Please help me to get this. Thanks
Upvotes: 2
Views: 59
Reputation: 117073
Try perhaps:
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:template match="*">
<xsl:copy>
<xsl:attribute name="xpath" select="ancestor-or-self::*/concat('/*:', local-name())" separator=""/>
<xsl:apply-templates select="@*|*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*">
<xsl:attribute name="{name()}" select="ancestor::*/concat('/*:', local-name()), concat('/@', local-name())" separator=""/>
</xsl:template>
</xsl:stylesheet>
The result here leaves out the text()
location step. I am not sure why you would need it but if you do, you can easily add it.
Note that attributes too can be in a namespace. Here we ignore this possibility.
Upvotes: 1