Manipulation XML having array in it
I have an incoming XML i wanted transform to another format . I am not getting desired result .
Incoming XML:
<aggResponse> <services> <serviceIdentifier>vStatus</serviceIdentifier> <Access>Allow</Access> </services> <services> <serviceIdentifier>vAccess</serviceIdentifier> <Access>Reject</Access> <ErrorCode>200504</ErrorCode> </services> <services> <serviceIdentifier>vLavel</serviceIdentifier> <Access>Allow</Access> </services> </aggResponse>
Need Output:
<NS1:Response xmlns:NS1="http://test.com"> <NS1:checkDetail> <NS1:Detail> <NS1:AuthCheckType>vStatus</NS1:AuthCheckType> <NS1:Result>Allow</NS1:Result> <NS1:ErrorCode /> <NS1:checkDetail /> </NS1:Detail> <NS1:Detail> <NS1:AuthCheckType>vAccess</NS1:AuthCheckType> <NS1:Result>Allow</NS1:Result> <NS1:ErrorCode /> <NS1:checkDetail /> </NS1:Detail> <NS1:Detail> <NS1:AuthCheckType>vLavel</NS1:AuthCheckType> <NS1:Result>Reject</NS1:Result> <NS1:ErrorCode>200504</NS1:ErrorCode> <NS1:checkDetail /> </NS1:Detail> </NS1:checkDetail> <NS1:Access>Reject</NS1:Access> <NS1:ErrorCode>200504</NS1:ErrorCode> </NS1:Response>
I am using the below XSLT to transform. XSLT:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dp="http://www.datapower.com/extensions" xmlns:dpconfig="http://www.datapower.com/param/config" version="1.0" extension-element-prefixes="dp" exclude-result-prefixes="dp dpconfig"> <xsl:output method="xml" /> <xsl:template match="/"> <xsl:variable name="overallAccess" select="'Allow'" /> <xsl:variable name="errorCode" select="0" /> <NS1:Response xmlns:NS1="http://test.com"> <NS1:checkDetail> <xsl:for-each select="//*[local-name()='aggResponse']/*[local-name()='services']"> <NS1:Detail> <NS1:AuthCheckType> <xsl:value-of select="*[local-name()='serviceIdentifier']" /> </NS1:AuthCheckType> <NS1:Result> <xsl:value-of select="*[local-name()='Access']" /> </NS1:Result> <NS1:ErrorCode> <xsl:value-of select="*[local-name()='ErrorCode']" /> </NS1:ErrorCode> <xsl:variable name="overallAccesstemp"> <xsl:value-of select="*[local-name()='Access']" /> </xsl:variable> <xsl:variable name="authAccess"> <xsl:choose> <xsl:when test="$overallAccesstemp='Reject'"> <xsl:variable name="overallAccess" select="'Reject'" /> <xsl:variable name="errorCode" select="*[local-name()='ErrorCode']" /> </xsl:when> <xsl:when test="$overallAccesstemp='Reject_needmorepoint' and $overallAccess='Allow' "> <xsl:variable name="overallAccess" select="'Reject_needmorepoint'" /> <xsl:variable name="errorCode" select="*[local-name()='ErrorCode']" /> </xsl:when> <xsl:otherwise> <xsl:variable name="overallAccess" select="'Allow'" /> <xsl:variable name="errorCode" select="0" /> </xsl:otherwise> </xsl:choose> </xsl:variable> <NS1:checkDetail /> </NS1:Detail> </xsl:for-each> </NS1:checkDetail> <NS1:Access> <xsl:value-of select="$authAccess" /> </NS1:Access> <NS1:ErrorCode> <xsl:value-of select="$errorCode" /> </NS1:ErrorCode> </NS1:Response> </xsl:template> </xsl:stylesheet>
Incoming XML is dynamic one meaning the "Access" tag value can be either 1. Allow 2. Reject 3. Reject_morepoint. . condition 1.so if all are like Allow then final Access is "Allow" condition 2. if at least one is Reject then final Access is Reject . Condition 3 if all are Reject_morepoint then final Access is Reject_morepoint. For Allow error code will be always 0 and all other case it should be the error code we are getting from incoming request .That is why i was trying to write the logic within for loop which is not quite working.
Can someone let me know what is the issue in the xslt. How to get the desired result
Is there a reason why you cannot do simply:
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="/aggResponse"> <NS1:Response xmlns:NS1="http://test.com"> <NS1:checkDetail> <xsl:for-each select="services"> <NS1:Detail> <NS1:AuthCheckType> <xsl:value-of select="serviceIdentifier"/> </NS1:AuthCheckType> <NS1:Result> <xsl:value-of select="Access"/> </NS1:Result> <NS1:ErrorCode> <xsl:value-of select="ErrorCode"/> </NS1:ErrorCode> <NS1:checkDetail/> </NS1:Detail> </xsl:for-each> </NS1:checkDetail> <xsl:variable name="access" select="services[serviceIdentifier='vAccess']" /> <NS1:Access> <xsl:value-of select="$access/Access" /> </NS1:Access> <NS1:ErrorCode> <xsl:value-of select="$access/ErrorCode" /> </NS1:ErrorCode> </NS1:Response> </xsl:template> </xsl:stylesheet>
P.S. There should never be a reason to use a hack like *[local-name()='xyz']
.
Added in response to your added requirement:
Here is an example implementing your 3 rules for populating the NS1:Access
element. As I mentioned in a comment to your question, these rules are not collectively exhaustive – so you will need to add to them in order to cover all possible scenarios:
<xsl:variable name="access" select="services/Access" /> <NS1:Access> <xsl:choose> <!-- 1. all are Allow --> <xsl:when test="not($access != 'Allow')">Allow</xsl:when> <!-- 2. at least one is Reject --> <xsl:when test="$access = 'Reject'">Reject</xsl:when> <!-- 3. all are Reject_morepoint --> <xsl:when test="not($access != 'Reject_morepoint')">Reject_morepoint</xsl:when> </xsl:choose> </NS1:Access>