I need to use variable in template match in xslt but I transformed template match into variable. I got syntax error.
This is my orginal xslt
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/name/name[not(telephoneNav/detail/action = 'A') and not(telephoneNav/detail/action = 'S')]"/>
<xsl:template match="detail[not(action = 'A') and not(action = 'S')]"/>
</xsl:stylesheet>
This is my xslt which has been transformed into variable in template match.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:variable name="actionXpath1" select="'/name/name[not(telephoneNav/detail/action = 'A') and not(telephoneNav/detail/action = 'S')]'" />
<xsl:variable name="actionXpath2" select="'detail[not(action = 'A') and not(action = 'S')]'" />
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="$actionXpath1"/>
<xsl:template match="$actionXpath2"/>
</xsl:stylesheet>
like this https://xsltfiddle.liberty-development.net/3MvmXiw
In XSLT 3 using static parameters and _match as a shadow attribute you can use
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0">
<xsl:param name="actionXpath1" static="yes" select="'/name/name[not(telephoneNav/detail/action = "A") and not(telephoneNav/detail/action = "S")]'" />
<xsl:param name="actionXpath2" static="yes" select="'detail[not(action = "A") and not(action = "S")]'" />
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template _match="{$actionXpath1}"/>
<xsl:template _match="{$actionXpath2}"/>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/3MvmXiw/1
So you need to use an XSLT 3 processor and you need to use it in a way that allows setting static parameters, i.e. use an API specialized for XSLT 3 to support setting such parameters before the stylesheet is compiled.
Related
Given the input XML data:
<Report_Entry>
<Time_Off_Type_Group>
<Time_Off_Type Descriptor="Sickness Full" />
</Time_Off_Type_Group>
<Time_Off_Type_Group>
<Time_Off_Type Descriptor="Sickness Part" />
</Time_Off_Type_Group>
<Time_Off_Entry_ID>2d90199913fa9fae8</Time_Off_Entry_ID>
<Request_or_Correction>Time Off Request</Request_or_Correction>
</Report_Entry>
As a result, I expect the output data via the condition: "for-each Time_Off_Type_Group move Time_Off_Entry_ID and Request_or_Correction into the Time_Off_Type_Group"
Output example:
<Report_Entry>
<Time_Off_Type_Group>
<Time_Off_Type Descriptor="Sickness Full" />
<Time_Off_Entry_ID>2d90199913fa9fae8</Time_Off_Entry_ID>
<Request_or_Correction>Time Off Request</Request_or_Correction>
</Time_Off_Type_Group>
<Time_Off_Type_Group>
<Time_Off_Type Descriptor="Sickness Part" />
<Time_Off_Entry_ID>2d90199913fa9fae8</Time_Off_Entry_ID>
<Request_or_Correction>Time Off Request</Request_or_Correction>
</Time_Off_Type_Group>
</Report_Entry>
Think templates not for-each, so write a template for the Time_Off_Type_Group elements copying the siblings as children and make sure the default idendity copying does not apply to those siblings:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output indent="yes"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Time_Off_Type_Group">
<xsl:copy>
<xsl:copy-of select="*, ../(* except Time_Off_Type_Group)"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Report_Entry/*[not(self::Time_Off_Type_Group)]"/>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/bEzkTcn
Or shortly:
<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="/Report_Entry">
<xsl:variable name="common" select="Time_Off_Entry_ID | Request_or_Correction" />
<xsl:copy>
<xsl:for-each select="Time_Off_Type_Group">
<xsl:copy>
<xsl:copy-of select="* | $common"/>
</xsl:copy>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
I need to change order of elements. But also rename elements into elements.
So,
I have xml:
<transactionality>
<rollbackexttransactionid>
<rollbackvalidity>3600</rollbackvalidity>
<rollbackscheduledattemps>3</rollbackscheduledattemps>
<manualcorrectionpath>TransactionalityLogs</manualcorrectionpath>
</rollbackexttransactionid>
<transactionalitylogspath>TransactionalityLogs</transactionalitylogspath>
<rollbacklifecycleevents>
<rollbacklifecycle>1200</rollbacklifecycle>
<rollbackscheduledattemps>2</rollbackscheduledattemps>
<manualcorrectionpath>TransactionalityLogs</manualcorrectionpath>
</rollbacklifecycleevents>
<rollbackpayment>
<rollbackvalidity>1200</rollbackvalidity>
<rollbackscheduledattemps>2</rollbackscheduledattemps>
<manualcorrectionpath>TransactionalityLogs</manualcorrectionpath>
</rollbackpayment>
</transactionality>
I need to do element transactionalitylogspath as first in to transactionality.
Rename all elements "rollbackscheduledattemps" to "rollbackscheduledattempts"
Rename rollbacklifecycleevents/rollbacklifecycle to rollbacklifecycleevents/rollbackvalidity
I would'like to have:
<transactionality>
<transactionalitylogspath>TransactionalityLogs</transactionalitylogspath>
<rollbackexttransactionid>
<rollbackvalidity>3600</rollbackvalidity>
<rollbackscheduledattempts>3</rollbackscheduledattempts>
<manualcorrectionpath>TransactionalityLogs</manualcorrectionpath>
</rollbackexttransactionid>
<rollbacklifecycleevents>
<rollbackvalidity>1200</rollbackvalidity>
<rollbackscheduledattempts>2</rollbackscheduledattempts>
<manualcorrectionpath>TransactionalityLogs</manualcorrectionpath>
</rollbacklifecycleevents>
<rollbackpayment>
<rollbackvalidity>1200</rollbackvalidity>
<rollbackscheduledattempts>2</rollbackscheduledattempts>
<manualcorrectionpath>TransactionalityLogs</manualcorrectionpath>
</rollbackpayment>
</transactionality>
I did:
<xsl:template match="transactionality">
<xsl:variable name="elements-after" select="rollbackexttransactionid|rollbacklifecycleevents|rollbackpayment"/>
<xsl:copy>
<xsl:copy-of select="transactionalitylogspath"/>
<xsl:copy-of select="$elements-after">
</xsl:copy-of >
</xsl:copy>
</xsl:template>
<xsl:template match="rollbackscheduledattemps">
<rollbackscheduledattempts>
<xsl:apply-templates select="#* | node()"/>
</rollbackscheduledattempts>
</xsl:template>
byt it doesn't work :(.
Help me please.
Here's how I would do it :
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="transactionality">
<xsl:copy>
<xsl:apply-templates select="transactionalitylogspath"/>
<xsl:apply-templates select="*[local-name() != 'transactionalitylogspath']"/>
</xsl:copy>
</xsl:template>
<xsl:template match="rollbackscheduledattemps">
<rollbackscheduledattempts>
<xsl:value-of select="."/>
</rollbackscheduledattempts>
</xsl:template>
<xsl:template match="rollbacklifecycleevents/rollbacklifecycle">
<rollbackvalidity>
<xsl:value-of select="."/>
</rollbackvalidity>
</xsl:template>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Here's a working example : https://xsltfiddle.liberty-development.net/6pS26mL
I have the following XML:
<segment>
<personal_information>
<birth_name>xxx</birth_name>
<created_by>yyy</created_by>
<created_on_timestamp>2018-08-06T06:41:07.000Z</created_on_timestamp>
</personal_information>
<segment>
I want to copy the entire personal_information segment with all elements and sub-segments while adding a new field. I tried this with:
<segment>
<personal_information>
<action>DELETE</action>
<xsl:copy>
<xsl:apply-templates select="child::node()"/>
</xsl:copy>
</personal_information>
</segment>
But this results in the following:
<segment>
<personal_information>
<action>DELETE</action>
<personal_information>
<birth_name>xxx</birth_name>
<created_by>yyy</created_by>
<created_on_timestamp>2018-08-06T06:41:07.000Z</created_on_timestamp>
</personal_information>
</personal_information>
</segment>
Would would be the XSLT code to achieve this as a result:
<segment>
<personal_information>
<action>DELETE</action>
<birth_name>xxx</birth_name>
<created_by>yyy</created_by>
<created_on_timestamp>2018-08-06T06:41:07.000Z</created_on_timestamp>
</personal_information>
</segment>
I do not want to copy all fields one by one.
Instead of using <xsl:copy>, use <xsl:copy-of>, which accepts an XPath expression for the nodes to be included in the copy; in this case only the inner childnodes.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="segment">
<segment>
<personal_information>
<action>DELETE</action>
<xsl:copy-of select="personal_information/*" />
</personal_information>
</segment>
</xsl:template>
</xsl:stylesheet>
You need a identity template and one personal_information with adding one action element:
<?xml version="1.0" encoding="UTF-8"?>
<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 indent="yes"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="personal_information">
<xsl:copy>
<action>DELETE</action>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Updated as per new requirement :
<?xml version="1.0" encoding="UTF-8"?>
<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 indent="yes"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="personal_information">
<action>DELETE</action>
<xsl:apply-templates select="node()"/>
</xsl:template>
</xsl:stylesheet>
input:
<?xml version="1.0" encoding="UTF-8" ?><DocumentCombined xmlns="http://xmlns.oracle.com/pcbpel/schema/ACCO_EDI_X12_Scheduledjobs/Write_867xmlfile">
<Header xmlns="">
<ISADATE>
<value-of/>
</ISADATE>
</Header>
</DocumentCombined>
here i need to remove the xmlns name spaces to the DocumentCombined element and Header elements.
output:
<?xml version="1.0">
<DocumentCombined>
<Header>
<ISADATE>
<value-of/>
</ISADATE>
</Header>
</DocumentCombined>
If you want to strip all namespaces simply use
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="#* | node()"/>
</xsl:element>
</xsl:template>
i have something like this:
<root>
<a>foo</a>
<b>bar</b>
<groupme>foobar</groupme>
<groupme>baz</groupme>
<groupme>42</groupme>
<c>abc</c>
<d>def</d>
<groupme>foo</groupme>
<x>xyz</x>
<groupme>bar</groupme>
<groupme>foo</groupme>
<z>thats it</z>
</root>
now i need all groume's which are direct neighbours to be a single node like:
<root>
<a>foo</a>
<b>bar</b>
<groupme>foobar baz 42</groupme>
<c>abc</c>
<d>def</d>
<groupme>foo</groupme>
<x>xyz</x>
<groupme>bar foo</groupme>
<z>thats it</z>
</root>
also the groupme nodes containing other nodes, i've just leave them to provide a simple example.
the groupme nodes only apear in a specific level, no groupme nodes in others then root.
any help for me?
Such grouping can be achieved with an approach called "sibling recursion", for your problem I would suggest a stylesheet as follows:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="root/groupme[not(preceding-sibling::*[1][self::groupme])]">
<xsl:copy>
<xsl:apply-templates select="node()"/>
<xsl:apply-templates select="following-sibling::*[1][self::groupme][1]" mode="list"/>
</xsl:copy>
</xsl:template>
<xsl:template match="root/groupme[preceding-sibling::*[1][self::groupme]]"/>
<xsl:template match="root/groupme[preceding-sibling::*[1][self::groupme]]" mode="list">
<xsl:text> </xsl:text>
<xsl:apply-templates select="node()"/>
<xsl:apply-templates select="following-sibling::*[1][self::groupme][1]" mode="list"/>
</xsl:template>
</xsl:stylesheet>
When applied to the input
<root>
<a>foo</a>
<b>bar</b>
<groupme>foobar</groupme>
<groupme>baz</groupme>
<groupme>42</groupme>
<c>abc</c>
<d>def</d>
<groupme>foo</groupme>
<x>xyz</x>
<groupme>bar</groupme>
<groupme>foo</groupme>
<z>thats it</z>
</root>
the result is
<root>
<a>foo</a>
<b>bar</b>
<groupme>foobar baz 42</groupme>
<c>abc</c>
<d>def</d>
<groupme>foo</groupme>
<x>xyz</x>
<groupme>bar foo</groupme>
<z>thats it</z>
</root>
As an alternative to the sibling recursion it is also possible to "grab" the following siblings with a key based approach:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:key
name="first"
match="root/groupme[preceding-sibling::*[1][self::groupme]]"
use="generate-id(preceding-sibling::groupme[not(preceding-sibling::*[1][self::groupme])][1])"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="root/groupme[not(preceding-sibling::*[1][self::groupme])]">
<xsl:copy>
<xsl:apply-templates select="node()"/>
<xsl:apply-templates select="key('first', generate-id())" mode="list"/>
</xsl:copy>
</xsl:template>
<xsl:template match="root/groupme[preceding-sibling::*[1][self::groupme]]"/>
<xsl:template match="root/groupme" mode="list">
<xsl:text> </xsl:text>
<xsl:apply-templates select="node()"/>
</xsl:template>
</xsl:stylesheet>