XSLT copy without segment name - xslt

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>

Related

XSLT - Removing root node and first child node and placing grand child as root

Need help in following logic.
Source XML --
<?xml version="1.0" encoding="UTF-8"?>
<multimap:Messages xmlns:multimap="http://somenamespace.com/xi/XI/SplitAndMerge">
<multimap:Message1>
<ns0:ToBeRoot xmlns:ns0="http://mynamespace.com">
<ns0:children_level1 xmlns:ns0="http://mynamespace.com">
<Somedata/>
</ns0:children_level1>
</ns0:ToBeRoot>
<ns0:ToBeRoot xmlns:ns0="http://mynamespace.com">
<ns0:children_level2 xmlns:ns0="http://mynamespace.com">
<Somedata/>
</ns0:children_level2>
</ns0:ToBeRoot>
</multimap:Message1>
</multimap:Messages>
Target XML (required)
<?xml version="1.0" encoding="UTF-8"?>
<ns0:ToBeRoot xmlns:ns0="http://mynamespace.com">
<ns0:children_level1 xmlns:ns0="http://mynamespace.com">
<Somedata/>
</ns0:children_level1>
<ns0:children_level2 xmlns:ns0="http://mynamespace.com">
<Somedata/>
</ns0:children_level2>
</ns0:ToBeRoot>
XSLT I tried,
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns0="http://somenamespace.com/xi/XI/SplitAndMerge">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="node() | #*">
<xsl:copy>
<xsl:apply-templates select="node() | #*"/>
</xsl:copy>
</xsl:template>
<!-- template for the document element -->
<xsl:template match="/*">
<xsl:apply-templates select="node()/node()/node()"/>
</xsl:template>
<xsl:template match="ToBeRoot">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
I think something needs to be added to the template
<xsl:template match="ToBeRoot">
but struggling, please help.
The output using the above XSLT
<?xml version="1.0" encoding="UTF-8"?>
<ns0:children_level1 xmlns:ns0="http://mynamespace.com" xmlns:multimap="http://somenamespace.com/xi/XI/SplitAndMerge">
<Somedata/>
</ns0:children_level1>
<ns0:children_level2 xmlns:ns0="http://mynamespace.com" xmlns:multimap="http://somenamespace.com/xi/XI/SplitAndMerge">
<Somedata/>
</ns0:children_level2>
The simplest way would be:
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="/*">
<ns0:ToBeRoot xmlns:ns0="http://mynamespace.com">
<xsl:copy-of select="*/*/*"/>
</ns0:ToBeRoot>
</xsl:template>
</xsl:stylesheet>
This leaves a redundant namespace declaration on the copied elements, which should be harmless. If you want to remove it, then you must recreate the elements instead of copying them:
<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="/*">
<ns0:ToBeRoot xmlns:ns0="http://mynamespace.com">
<xsl:apply-templates select="*/*/*"/>
</ns0:ToBeRoot>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{name()}" namespace="{namespace-uri()}">
<xsl:copy-of select="#*"/>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Or, if your processor supports it:
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="/*">
<ns0:ToBeRoot xmlns:ns0="http://mynamespace.com">
<xsl:copy-of select="*/*/*" copy-namespaces="no"/>
</ns0:ToBeRoot>
</xsl:template>
</xsl:stylesheet>
Added:
is it feasible to get the name ns0:ToBeRoot dynamically from the payload
Yes. Instead of:
<ns0:ToBeRoot xmlns:ns0="http://mynamespace.com">
<!-- ... -->
</ns0:ToBeRoot>
use:
<xsl:element name="{name(*/*[1])}" namespace="{namespace-uri(*/*[1])}">
<!-- ... -->
</xsl:element>
It sounds as if you want
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns0="http://mynamespace.com"
version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="*/*/ns0:ToBeRoot[1]"/>
</xsl:template>
<xsl:template match="ns0:ToBeRoot">
<xsl:copy>
<xsl:apply-templates select="node() | following-sibling::ns0:ToBeRoot/node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
or perhaps better XSLT 2 or 3:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns0="http://mynamespace.com"
version="2.0">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="#* | node()">
<xsl:copy copy-namespaces="no">
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="*/*/ns0:ToBeRoot[1]"/>
</xsl:template>
<xsl:template match="ns0:ToBeRoot">
<xsl:copy copy-namespaces="no">
<xsl:apply-templates select="node() | following-sibling::ns0:ToBeRoot/node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
You had some mixup in your namespace declaration: xmlns:ns0 was "http://mynamespace.com" in your XML, but "http://somenamespace.com/xi/XI/SplitAndMerge" in your XSLT.
Synchronizing them would give you the following XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns0="http://mynamespace.com" xmlns:multimap="http://somenamespace.com/xi/XI/SplitAndMerge">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="node() | #*">
<xsl:copy>
<xsl:apply-templates select="node() | #*"/>
</xsl:copy>
</xsl:template>
<!-- template for the document element -->
<xsl:template match="/multimap:Messages">
<xsl:element name="ns0:ToBeRoot" namespace="http://mynamespace.com">
<xsl:apply-templates select="multimap:Message1/ns0:ToBeRoot/ns0:*" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
It will give you the desired output:
<?xml version="1.0" encoding="UTF-8"?>
<ns0:ToBeRoot xmlns:ns0="http://mynamespace.com">
<ns0:children_level1>
<Somedata/>
</ns0:children_level1>
<ns0:children_level2>
<Somedata/>
</ns0:children_level2>
</ns0:ToBeRoot>

XSL Move one level Element into other while last one is appearing

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>

Xslt copy element to existing or create new if not exists

Pretty new to xml transformations and i'm stuck at (might be for you) pretty easy task.
Let's suggest we have source:
<root>
<someValue>123</someValue>
</root>
It should be transformed into:
<root>
<additional>
<someValue>123</someValue>
</additional>
</root>
But if we have this as a source:
<root>
<additional>
<b>something</b>
</additional>
<someValue>123</someValue>
</root>
we should move someValue to existing additional, i.e.:
<root>
<additional>
<b>something</b>
<someValue>123</someValue>
</additional>
</root>
Keep in mind that there can be other elements at a level with same behavior (moved under additional).
Well, working example is much appreciated, but if it is accompanied by small description of how it works that would be fantastic (i prefer be tought to fish, rather than just being fed with it).
One possible approach would be to add a additional wrapper as a child of root, and remove the existing additional wrapper - so its children move up to become children of root (or rather children of the added additional wrapper):
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:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root">
<xsl:copy>
<additional>
<xsl:apply-templates/>
</additional>
</xsl:copy>
</xsl:template>
<xsl:template match="additional">
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
Keep in mind that there can be other elements at a level with same
behavior (moved under additional).
This stylesheet:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="root[additional|someValue]">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<additional>
<xsl:apply-templates select="additional/*|someValue"/>
</additional>
<xsl:apply-templates select="node()[not(self::additional|self::someValue)]"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
With this input:
<root>
<additional>
<b>something</b>
</additional>
<someValue>123</someValue>
<anotherValue>keep</anotherValue>
</root>
Output:
<root>
<additional>
<b>something</b>
<someValue>123</someValue>
</additional>
<anotherValue>keep</anotherValue>
</root>
Do note: just one rule to override the identity transformation. Only process root meeting the conditions (someValue or additional childs). Copying root, applying templates to attributes (to further process), wrapping with an additional element the result of applying templates to additional's childs and root's someValue childs. Finally, applying templates to root's childs, which are not additional nor someValue.
I ended up with following:
<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:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root/additional"/>
<xsl:template match="/root">
<xsl:copy>
<additional>
<xsl:copy-of select="someValue"/>
<xsl:copy-of select="additional/*"/>
</additional>
</xsl:copy>
</xsl:template>
Here we strip original additional and then create it from scratch copying there needed someValue and original content from source (additional/*)
Use for version xslt 2.0
<?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 method="xml" omit-xml-declaration="no" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node() except someValue"/>
</xsl:copy>
</xsl:template>
<xsl:template match="additional">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
<xsl:copy-of select="following-sibling::someValue"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

xslt copy child note and add extra nodes

For the following xml:
<root>
<employees>
<employee>
<Name>ABC</Name>
<Dept>CS</Dept>
<Designation>sse</Designation>
</employee>
</employees>
</root>
I use this xslt:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<!-- Identity transform -->
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Name">
<xsl:copy-of select="."/>
<Age>34</Age>
</xsl:template>
<xsl:template match="Dept">
<xsl:copy-of select="."/>
<Domain>Insurance</Domain>
</xsl:template>
</xsl:stylesheet>
I would like to achieve the following output
<employee>
<Name>ABC</Name>
<Age>34</Age>
<Dept>CS</Dept>
<Domain>Insurance</Domain>
<Designation>sse</Designation>
</employee>
I don't know what xpath shall I use to limit the result only to employee node.
Well, processing starts at the document node (root node) denoted by / thus if you write a template
<xsl:template match="/">
<xsl:apply-templates select="//employee"/>
</xsl:template>
you only process any employee descendants of the document with the rest of the templates.
See https://xsltfiddle.liberty-development.net/pPqsHT6 for a working demo of above suggestion integrated into your stylesheet, the whole code is
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- Identity transform -->
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Name">
<xsl:copy-of select="."/>
<Age>34</Age>
</xsl:template>
<xsl:template match="Dept">
<xsl:copy-of select="."/>
<Domain>Insurance</Domain>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="//employee"/>
</xsl:template>
</xsl:stylesheet>

How can we convert XML elements into a different namespace in xslt

I have an input xml
<Request xmlns="http://hgkg.ghg.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<AppointmentInfo xmlns="">
<AppointmentId/>
<CountryCode>US</CountryCode>
<Division>A</Division>
</AppointmentInfo>
<AppointDate xmlns="">
<Day>Monday</Day>
<Date>April 2</Date>
<AppointDate>
</Request>
I need output like this
<Request xmlns="http://hgkg.ghg.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<AppointmentInfo>
<AppointmentId/>
<CountryCode>US</CountryCode>
<Division>A</Division>
</AppointmentInfo>
<AppointDate>
<Day>Monday</Day>
<Date>April 2</Date>
<AppointDate>
</Request>
i just want to remove xmlns="" in that and assume response AppointmentInfo and AppointDate are in hgkg namespace.I want to transform to it..
please help me
Building on JLRishe's earlier answer, you could try this:
<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:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*/*">
<xsl:element name="{name()}" namespace="{namespace-uri(/*)}">
<xsl:apply-templates select="#* | node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
This would mean, each element that is not the outermost element (match="*/*") is copied to an output element with the same name, but with the namespace of the outermost element (namespace-uri(/*)).
See if that works...