blank Attribute with value in XML with XSLT transformation - xslt

I have below XMl and I need to replace root="" with Dynamic GUID value. this can be anywhere in XML document. it does not work with below XSLT. This is just the extended text to post successfully.
<ClinicalDocument xmlns="urn:hl7-org:v3">
<templateId root="2.16.840.1.113883.10.20.22.1.2" extension="2015-08-01"/>
<id root=""/>
<code code="34133-9" codeSystem="2.16.840.1.113883.6.1" codeSystemName="LN"
displayName="Summarization of Episode Note"/>
<title>Patient Summary Document</title>
<languageCode code="en-US"/>
<component>
<structuredBody>
<component>
<section>
<templateId root="2.16.840.1.113883.10.20.22.2.6.1"/>
<entry typeCode="DRIV">
<act classCode="ACT" moodCode="EVN">
<templateId root="2.16.840.1.113883.10.20.22.4.30"/>
<templateId root="2.16.840.1.113883.10.20.22.4.30" extension="2015-08-01"/>
<id nullFlavor="UNK"/>
<informant>
<assignedEntity>
<id root="2.16.840.1.113883.3.86.3.1" extension="STHS"/>
<addr nullFlavor="UNK"/>
<telecom nullFlavor="UNK"/>
<assignedPerson>
<name nullFlavor="UNK"/>
</assignedPerson>
<representedOrganization>
<id root="" extension="STHS" displayable="true"/>
<name>STHS</name>
<telecom nullFlavor="UNK"/>
<addr nullFlavor="UNK"/>
</representedOrganization>
</assignedEntity>
</informant>
</act>
</entry>
</section>
</component>
</structuredBody>
</component>
</ClinicalDocument>
I have below XSLT. but it does not work for above highlighted tag.
<xsl:variable name="GUID" select="'FF1122'"/>
<xsl:template match="id/#root[.='']">
<xsl:attribute name="root">
<xsl:value-of select="$GUID"/>
</xsl:attribute>
</xsl:template>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:isc="http://extension-functions.intersystems.com"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns1="urn:hl7-org:v3">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="GUID" select="'FF1122'"/>
<xsl:template match="ns1:id/#root[.='']">
<xsl:attribute name="root">
<xsl:value-of select="$GUID"/>
</xsl:attribute>
</xsl:template>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

Related

Remove duplicate parent node based on child node and add specific element values in the concerning node

I want to sum the value's "TotalAmount" and "Tax" with //Category/ID as unique value. The XSLT has to delete the duplicate(s) and sum the values of the deleted duplicate. So for this example, the unique ID "S" is a duplicate and should be deleted and the required values should be added to the other "S". I'm not able to make the XSLT working.
Input example:
<root>
<Total>
<TotalAmount currencyID="EUR">100.00</TotalAmount>
<Tax currencyID="EUR">20.00</Tax>
<Category>
<ID>S</ID>
<Percent>21.000</Percent>
<Description>
<ID>Note</ID>
</Description>
</Category>
</Total>
<Total>
<TotalAmount currencyID="EUR">150.00</TotalAmount>
<Tax currencyID="EUR">20.00</Tax>
<Category>
<ID>S</ID>
<Percent>21.000</Percent>
<Description>
<ID>Note</ID>
</Description>
</Category>
</Total>
<Total>
<TotalAmount currencyID="EUR">200.00</TotalAmount>
<Tax currencyID="EUR">0</Tax>
<Category>
<ID>O</ID>
<Percent>0</Percent>
<Description>
<ID>Note</ID>
</Description>
</Category>
</Total>
</root>
XSLT
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kByP" match="Category" use="ID"/>
<xsl:template match="node()|#*">
<xsl:param name="pNewValue"/>
<xsl:copy>
<xsl:apply-templates select="node()|#*">
<xsl:with-param name="pNewValue" select="$pNewValue"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match=
"Category[generate-id()
=
generate-id(key('kByP', ID)[1])
]">
<xsl:copy>
<xsl:apply-templates select="node()|#*">
<xsl:with-param name="pNewValue" select=
"sum(key('kByP', ID)/TotalAmount)"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="Total"/>
<xsl:template match="TotalAmount/text()">
<xsl:param name="pNewValue"/>
<xsl:value-of select="$pNewValue"/>
</xsl:template>
</xsl:stylesheet>
Required output:
<root>
<Total>
<TotalAmount currencyID="EUR">250.00</TotalAmount>
<Tax currencyID="EUR">40.00</Tax>
<Category>
<ID>S</ID>
<Percent>21.000</Percent>
<Description>
<ID>Note</ID>
</Description>
</Category>
</Total>
<Total>
<TotalAmount currencyID="EUR">200.00</TotalAmount>
<Tax currencyID="EUR">0</Tax>
<Category>
<ID>O</ID>
<Percent>0</Percent>
<Description>
<ID>Note</ID>
</Description>
</Category>
</Total>
</root>
I would start with the identity transformation template plus the key you have changed to <xsl:key name="kByP" match="Total" use="Category/ID"/>, then have
<xsl:template match="Total[not(generate-id() = generate-id(key('kByP', Category/ID)[1]))]"/>
and then
<xsl:template match="TotalAmount | Tax">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:value-of select="sum(key('kByP', ../Category/ID)/*[name() = name(current())])"/>
</xsl:copy>
</xsl:template>
So the full code is
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:key name="kByP" match="Total" use="Category/ID"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Total[not(generate-id() = generate-id(key('kByP', Category/ID)[1]))]"/>
<xsl:template match="TotalAmount | Tax">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:value-of select="format-number(sum(key('kByP', ../Category/ID)/*[name() = name(current())]), '0.00')"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

Moving a element sequence value to other element sequence

I have a certain requirement where, I need to move the sequence element values to another newly created element according to the the number of values in the original sequence.
Please find my Input XML and the Desired Output XML .
help is highly appreciated
Rule:
Move the value of Addr1 (catalogue/cd11/Location/Addr/Addr1) to
catalogue/cd11/Location/primary/original/Address1/place. primary/original/Address1/place need to be created.
Input XML:
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns="http://www.altova.com">
<publisher>
<Name id="d123">
<Place>Chicago</Place>
</Name
<catalogue id="d1" >
<cd11 id="d2">
<title>Empire Burlesque</title>
<artist>Bob Dylan</artist>
<year>1985</year>
<Location id="d1234">
<Addr id="d234">
<Addr1 id="d565">catherine Av</Addr1>
<Addr2 id="d566">block a</Addr2>
<City id="d567">chicago</City>
</Addr>
<Addr id="d334">
<Addr1 id="d665">Illinois st</Addr1>
<Addr2 id="d666">block a</Addr2>
<City id="d667">chicago</City>
</Addr>
</Location>
</cd11>
</catalogue>
<catalogue id="d3" >
<cd11 id="d4">
<title>Jurassic World</title>
<artist>Chris Pratt</artist>
</cd11>
</catalogue>
</publisher>
</root>
Output XML:
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns="http://www.example.com">
<publisher>
<Name id="d123">
<Place>Chicago</Place>
</Name>
<catalogue id="d1">
<cd11 id="d2">
<title>Empire Burlesque</title>
<artist>Bob Dylan</artist>
<year>1985</year>
<Location id="d1234">
<Addr id="d234">
<Addr1 id="d565">catherine Av</Addr1>
<Addr2 id="d566">block a</Addr2>
<City id="d567">chicago</City>
</Addr>
<Addr id="d334">
<Addr1 id="d665">Illinois st</Addr1>
<Addr2 id="d666">block a</Addr2>
<City id="d667">chicago</City>
</Addr>
<primary>
<original>
<test>test value</test>
<Address1>
<place>catherine Av</place>
</Address1>
<Address1>
<place>Illinois st</place>
</Address1>
</original>
</primary>
</Location>
</cd11>
</catalogue>
<catalogue id="d3">
<cd11 id="d4">
<title>Jurassic World</title>
<artist>Chris Pratt</artist>
</cd11>
</catalogue>
</publisher>
</root>
Thanks in advance.
You can write a template for Location elements that inserts the new elements and transforms the Addr1 elements:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
xpath-default-namespace="http://www.altova.com" xmlns="http://www.altova.com">
<xsl:output indent="yes"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="catalogue/cd11/Location">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
<primary>
<original>
<Address1>
<xsl:apply-templates select="Addr/Addr1" mode="convert"/>
</Address1>
</original>
</primary>
</xsl:copy>
</xsl:template>
<xsl:template match="Addr/Addr1" mode="convert">
<place>
<xsl:value-of select="."/>
</place>
</xsl:template>
</xsl:transform>
Online sample at http://xsltransform.net/ncdD7mv.
According to your comment and edit you do not want to copy the elements, instead you want to transform them to a new namespace, so you need to change all uses of xsl:copy of an element to create an element of the same local name but with the new namespace (which will simply work if you have the right xmlns="http://www.example.com" in the XSLT and use xsl:element name="{local-name()}"):
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
xpath-default-namespace="http://www.altova.com" xmlns="http://www.example.com">
<xsl:output indent="yes"/>
<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>
<xsl:template match="catalogue/cd11/Location">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="#* | node()"/>
<primary>
<original>
<Address1>
<xsl:apply-templates select="Addr/Addr1" mode="convert"/>
</Address1>
</original>
</primary>
</xsl:element>
</xsl:template>
<xsl:template match="Addr/Addr1" mode="convert">
<place>
<xsl:value-of select="."/>
</place>
</xsl:template>
</xsl:transform>

XSLT Convert attribute to element and copy value from an other elemen

I have XML data like this
<ABC version="1.0">
<XYZ>
<ROWSET ROWS="00001">
<ROWDEF>
<COLUMN ID="ACCT_ID" LEN="016" NULL="Y"/>
<COLUMN ID="AGNT_ID" LEN="004" NULL="Y"/>
<COLUMN ID="CUST_EXTR_ID" LEN="024" NULL="Y"/>
<COLUMN ID="PI_ID" LEN="019" NULL="Y"/>
<COLUMN ID="PRIN_ID" LEN="004" NULL="Y"/>
<COLUMN ID="SYS_ID" LEN="004" NULL="Y"/>
</ROWDEF>
<ROW>
<C>6369921501000060</C>
<C>0000</C>
<C>C13093102141063422034238</C>
<C>6369921501000060 </C>
<C>1500</C>
<C>9008</C>
</ROW>
<ROW>
<C>6369921501000061</C>
<C>0001</C>
<C>C13093102141063422034231</C>
<C>6369921501000060 </C>
<C>1501</C>
<C>9001</C>
</ROW>
</ROWSET>
</XYZ>
</ABC>
And I'm trying to convert this into
<?xml version="1.0" encoding="utf-8"?>
<ABC version="1.0">
<XYZ RC="0067">
<ROWSET ROWS="00001">
<ROWDEF>
<ACCT_ID>6369921501000060</ACCT_ID>
<AGNT_ID>0000</AGNT_ID>
<CUST_EXTR_ID>C13093102141063422034238</CUST_EXTR_ID>
<PI_ID>6369921501000060</PI_ID>
<PRIN_ID>1500</PRIN_ID>
<SYS_ID>9008</SYS_ID>
</ROWDEF>
<ROWDEF>
<ACCT_ID>6369921501000061</ACCT_ID>
<AGNT_ID>0001</AGNT_ID>
<CUST_EXTR_ID>C13093102141063422034231</CUST_EXTR_ID>
<PI_ID>6369921501000060</PI_ID>
<PRIN_ID>1501</PRIN_ID>
<SYS_ID>9001</SYS_ID>
</ROWDEF>
</ROWSET>
</XYZ>
</ABC>
I have looked around and tried few things but it is not working.
Can someone help me with this.
Below is my XSLT. Thanks in advance.
<?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="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="COLUMN">
<xsl:element name="{#ID}">
<xsl:copy>
<xsl:apply-templates select="node()"></xsl:apply-templates>
</xsl:copy>
<xsl:apply-templates />
<!--<xsl:call-template name="value"></xsl:call-template>-->
</xsl:element>
</xsl:template>
<!--
<xsl:template match="ROW" name="value">
<xsl:copy>
<xsl:apply-templates select="node()"></xsl:apply-templates>
</xsl:copy>
</xsl:template>
-->
</xsl:stylesheet>
This stylesheet will mostly do what you want, but I cannot fathom how to generate the attribute for <XYZ RC="0067">.
For each ROWSET it comes across it saves the ROWDEF element in a variable, copies all attribute nodes, and then processes each ROW element. The position of each C element in the ROW is caclulated, and the COLUMN in the corresponding position within the stored ROWDEF element is used to fetch an element name from the ID attribute.
<?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:strip-space elements="*"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="ROWSET">
<xsl:variable name="columns" select="ROWDEF/COLUMN"/>
<xsl:copy>
<xsl:apply-templates select="#*" />
<xsl:for-each select="ROW">
<ROWDEF>
<xsl:for-each select="C">
<xsl:variable name="pos" select="position()"/>
<xsl:element name="{$columns[$pos]/#ID}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:for-each>
</ROWDEF>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
output
<?xml version="1.0" encoding="utf-8"?>
<ABC version="1.0">
<XYZ>
<ROWSET ROWS="00001">
<ROWDEF>
<ACCT_ID>6369921501000060</ACCT_ID>
<AGNT_ID>0000</AGNT_ID>
<CUST_EXTR_ID>C13093102141063422034238</CUST_EXTR_ID>
<PI_ID>6369921501000060 </PI_ID>
<PRIN_ID>1500</PRIN_ID>
<SYS_ID>9008</SYS_ID>
</ROWDEF>
<ROWDEF>
<ACCT_ID>6369921501000061</ACCT_ID>
<AGNT_ID>0001</AGNT_ID>
<CUST_EXTR_ID>C13093102141063422034231</CUST_EXTR_ID>
<PI_ID>6369921501000060 </PI_ID>
<PRIN_ID>1501</PRIN_ID>
<SYS_ID>9001</SYS_ID>
</ROWDEF>
</ROWSET>
</XYZ>
</ABC>

Add parent element and rename the child element

I am trying to loop child elements under import and export. Create a parent element fields and put all the elements which the name is field into it, just under import, not include the elements field under structure, Create element structures over all elements structure, and the last work is rename all the element with the value of attribute name. I just know copy all of them first and can not go to next step to create the right template.
input:
<?xml version='1.0'?>
<jco name="TEST" timestamp="1275691115508" version="1.0">
<import>
<field name="RESERVED_IN">12345</field>
<structure name="GM_HEADER">
<field name="PSTNG_DATE">2004-07-02</field>
<field name="DOC_DATE">2004-04-02</field>
</structure>
<structure name="TESTRUN">
<field name="TESTRUN"></field>
</structure>
</import>
<export>
<field name="RESERVED_OUT"></field>
<structure name="GM_HEADER_RET">
<field name="MAT_DOC"></field>
<field name="DOC_YEAR">0000</field>
</structure>
</export>
</jco>
desired output:
<?xml version="1.0" ?>
<jco version="1.0" name="TEST">
<import>
<fields>
<RESERVED_IN>12345</RESERVED_IN>
</fields>
<structures>
<GM_HEADER>
<PSTNG_DATE>2004-07-02</PSTNG_DATE>
<DOC_DATE>2004-04-02</DOC_DATE>
</GM_HEADER>
<TESTRUN>
<TESTRUN></TESTRUN>
</TESTRUN>
</structures>
</import>
<export>
<fields>
<RESERVED_OUT></RESERVED_OUT>
</fields>
<structures>
<GM_HEADER_RET>
<MAT_DOC></MAT_DOC>
<DOC_YEAR>0000</DOC_YEAR>
</GM_HEADER_RET>
</structures>
</export>
</jco>
Below is my xslt, but it seems messed up.
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*" />
</xsl:copy>
</xsl:template>
<xsl:template match="import">
<fields>
<xsl:for-each select="/field">
<xsl:call-template name="field" />
</xsl:for-each>
</fields>
<structures>
<xsl:for-each select="/structure">
<xsl:element name="{#name}">
<xsl:value-of select="." />
</xsl:element>
<xsl:call-template name="field" />
</xsl:for-each>
</structures>
</xsl:template>
<xsl:template name="field">
<xsl:for-each select="/field">
<xsl:element name="{#name}">
<xsl:value-of select="." />
</xsl:element>
</xsl:for-each>
</xsl:template>
Use templates and apply-templates, not for-each, and it works out rather elegantly:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* , node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="import | export">
<xsl:copy>
<fields>
<xsl:apply-templates select="field"/>
</fields>
<structures>
<xsl:apply-templates select="structure"/>
</structures>
</xsl:copy>
</xsl:template>
<xsl:template match="field | structure">
<xsl:element name="{#name}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>

Adding a namespace to just one element

How do I only add a namespace to the root element?
My XML:
<Envelope>
<from>
<contents />
</from>
</Envelope>
My desired output:
<Envelope xmlns:tns="Foo">
<from>
<contents />
</from>
</Envelope>
I can only get "xmlns='Foo'" using this, not "xmlns:tns=..":
<xsl:element name="{local-name()}" namespace="Foo" >
<xsl:copy-of select="attribute::*"/>
<xsl:apply-templates />
</xsl:element>
Here is a complete transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:tns="Foo">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<xsl:element name="{name()}">
<xsl:copy-of select=
"document('')/*/namespace::*[name()='tns']"/>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the provided XML document:
<Envelope>
<from>
<contents />
</from>
</Envelope>
the wanted, correct result is produced:
<Envelope xmlns:tns="Foo">
<from>
<contents/>
</from>
</tns:Envelope>