Need to move PI to inside the root element - xslt

I have an xml file that starts with processing instruction at the top. So, I need to replace this PI('?change' not '?xml') to inside the root element. I mean below scenario is the original and look at the PI
<?xml version="1.0" encoding="UTF-8"?>
<?change id="69817" type="addition" mark="start"?>
<part id="PARTIII">
<title><p just="center" fli="0" li="0" ri="0" before="1" after="1">PART 3</p>
<p fli="0" li="0" ri="0" just="center" before="0"><font size="normal" smallcaps="yes">Mergers and Acquisitions</font></p></title>
<div class="annotations">
So, I need to move the first PI(change) that is before root element to inside the root element. How i can achieve this. Any help?
I mean the above code should be(look at the PI 'change')
<?xml version="1.0" encoding="UTF-8"?>
<part id="PARTIII"><?change id="69817" type="addition" mark="start"?>
<title><p just="center" fli="0" li="0" ri="0" before="1" after="1">PART 3</p>
<p fli="0" li="0" ri="0" just="center" before="0"><font size="normal" smallcaps="yes">Mergers and Acquisitions</font></p></title>
<div class="annotations">

try the following stylesheet:
<?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="processing-instruction()[following-sibling::part]"/>
<xsl:template match="part">
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:copy-of select="preceding-sibling::processing-instruction()"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

Related

How to check contain only characters + space and `p` using regex

I want to check to contain only characters + space and <p> nodes inside <used>.
Input:
<root>
<used><p>String 1</p></used>
<used>string 2<p>string 3</p></used>
<used>string 4</used>
<used><image>aaa.jpg</image>para</used>
The output should be:
<ans>
<abc>string 1</abc>
<abc>string 4</abc>
</ans>
Tried code:
<ans>
<abc>
<xsl:template match="root">
<xsl:choose>
<xsl: when test="getCode/matches(text(),'^[a-zA-Z0-9]+$')">
<xsl:text>text()</xsl:text>
</xsl:when>
</xsl:choose>
</xsl:template>
</abc>
</ans>
My tried code is not working as I am expecting. How can I fix this? Thank you. I am using XSLT 2.0
You can use the following XSLT-2.0 stylesheet to get the desired result:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl= "http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<!-- Handle the <root> element -->
<xsl:template match="/root">
<ans>
<xsl:apply-templates select="used" />
</ans>
</xsl:template>
<!-- Create <abc> elements for every matching element -->
<xsl:template match="used[not(*) and matches(text(),'^[\sa-zA-Z0-9]+$')] | used[not(text()) and matches(p/text(),'^[\sa-zA-Z0-9]+$')]/p">
<abc><xsl:copy-of select="text()" /></abc>
</xsl:template>
<!-- Remove all spurious text nodes -->
<xsl:template match="text()" />
</xsl:stylesheet>
Its result is
<?xml version="1.0" encoding="UTF-8"?>
<ans>
<abc>String 1</abc>
<abc>string 4</abc>
</ans>

I tried to remove specific element if its output is empty in XSLT

I am trying to remove Error Description element if it contains empty value using xslt. i tried lot of options but it does not work.
For example if inside Acknowledgement all the element get null then output get empty acknowledgement so I want remove acknowledgement element empty tag.
below is xml and xslt
<?xml version="1.0" encoding="UTF-8" ?>
<updateDocumentStatusResponse xmlns="http://xmlns.be/CommgrService_Message/v001">
<Acknowledgement>
<Result>SUCCESS</Result>
<ErrorCode>ErrorCode1375</ErrorCode>
<ErrorDescription></ErrorDescription>
</Acknowledgement>
</updateDocumentStatusResponse>
XSLT :
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:ns1="http://xmlns.be/CSM/v001" xmlns:mhdr="http://www.oracle.com/XSL/Transform/java/oracle.tip.mediator.service.common.functions.MediatorExtnFunction" xmlns:oraext="http://www.oracle.com/XSL/Transform/java/oracle.tip.pc.services.functions.ExtFunc" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xp20="http://www.oracle.com/XSL/Transform/java/oracle.tip.pc.services.functions.Xpath20" xmlns:xref="http://www.oracle.com/XSL/Transform/java/oracle.tip.xref.xpath.XRefXPathFunctions" xmlns:socket="http://www.oracle.com/XSL/Transform/java/oracle.tip.adapter.socket.ProtocolTranslator" xmlns:oracle-xsl-mapper="http://www.oracle.com/xsl/mapper/schemas" xmlns:dvm="http://www.oracle.com/XSL/Transform/java/oracle.tip.dvm.LookupValue" xmlns:oraxsl="http://www.oracle.com/XSL/Transform/java" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns0="http://xmlns.be/CommgrService_Message/v001" exclude-result-prefixes=" xsd oracle-xsl-mapper xsi xsl ns1 ns0 mhdr oraext xp20 xref socket dvm oraxsl"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
<oracle-xsl-mapper:schema>
<oracle-xsl-mapper:mapSources>
<oracle-xsl-mapper:source type="WSDL">
<oracle-xsl-mapper:schema location="../WSDLs/CommgrService_v001.wsdl"/>
<oracle-xsl-mapper:rootElement name="updateDocumentStatusResponse" namespace="http://xmlns.be/CommgrService_Message/v001"/>
</oracle-xsl-mapper:source>
</oracle-xsl-mapper:mapSources>
</oracle-xsl-mapper:schema>
<!--User Editing allowed BELOW this line - DO NOT DELETE THIS LINE-->
<xsl:template match="/">
<ns1:Output>
<ns1:CommunicationResponse>
<ns1:Acknowledgement>
<ns1:Result>
<xsl:value-of select="/ns0:updateDocumentStatusResponse/ns0:Acknowledgement/ns0:Result"/>
</ns1:Result>
<ns1:ErrorCode>
<xsl:value-of select="/ns0:updateDocumentStatusResponse/ns0:Acknowledgement/ns0:ErrorCode"/>
</ns1:ErrorCode>
<ns1:ErrorDescription>
<xsl:value-of select="/ns0:updateDocumentStatusResponse/ns0:Acknowledgement/ns0:ErrorDescription"/>
</ns1:ErrorDescription>
</ns1:Acknowledgement>
</ns1:CommunicationResponse>
</ns1:Output>
</xsl:template>
</xsl:stylesheet>
how can i achieve this?
I think this can be done if you're not thinking something big:
<xsl:if test="normalize-space(/ns0:updateDocumentStatusResponse/ns0:Acknowledgement/ns0:ErrorDescription) != ''">
<ns1:ErrorDescription>
<xsl:value-of select="/ns0:updateDocumentStatusResponse/ns0:Acknowledgement/ns0:ErrorDescription"/>
</ns1:ErrorDescription>
</xsl:if>
Edit:
One way to achieve this using extension function like exsl:node-set or msxsl:node-set to be able to further process a result tree fragment created in another template:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:ns1="http://xmlns.be/CSM/v001" xmlns:mhdr="http://www.oracle.com/XSL/Transform/java/oracle.tip.mediator.service.common.functions.MediatorExtnFunction" xmlns:oraext="http://www.oracle.com/XSL/Transform/java/oracle.tip.pc.services.functions.ExtFunc" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xp20="http://www.oracle.com/XSL/Transform/java/oracle.tip.pc.services.functions.Xpath20" xmlns:xref="http://www.oracle.com/XSL/Transform/java/oracle.tip.xref.xpath.XRefXPathFunctions" xmlns:socket="http://www.oracle.com/XSL/Transform/java/oracle.tip.adapter.socket.ProtocolTranslator" xmlns:oracle-xsl-mapper="http://www.oracle.com/xsl/mapper/schemas" xmlns:dvm="http://www.oracle.com/XSL/Transform/java/oracle.tip.dvm.LookupValue" xmlns:oraxsl="http://www.oracle.com/XSL/Transform/java" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns0="http://xmlns.be/CommgrService_Message/v001" exclude-result-prefixes=" xsd oracle-xsl-mapper xsi xsl ns1 ns0 mhdr oraext xp20 xref socket dvm oraxsl"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
<oracle-xsl-mapper:schema>
<oracle-xsl-mapper:mapSources>
<oracle-xsl-mapper:source type="WSDL">
<oracle-xsl-mapper:schema location="../WSDLs/CommgrService_v001.wsdl" />
<oracle-xsl-mapper:rootElement name="updateDocumentStatusResponse" namespace="http://xmlns.be/CommgrService_Message/v001" />
</oracle-xsl-mapper:source>
</oracle-xsl-mapper:mapSources>
</oracle-xsl-mapper:schema>
<!--User Editing allowed BELOW this line - DO NOT DELETE THIS LINE -->
<xsl:template match="/">
<xsl:variable name="result">
<ns1:Output>
<ns1:CommunicationResponse>
<ns1:Acknowledgement>
<ns1:Result>
<xsl:value-of select="/ns0:updateDocumentStatusResponse/ns0:Acknowledgement/ns0:Result" />
</ns1:Result>
<ns1:ErrorCode>
<xsl:value-of select="/ns0:updateDocumentStatusResponse/ns0:Acknowledgement/ns0:ErrorCode" />
</ns1:ErrorCode>
<ns1:ErrorDescription>
<xsl:value-of select="/ns0:updateDocumentStatusResponse/ns0:Acknowledgement/ns0:ErrorDescription" />
</ns1:ErrorDescription>
</ns1:Acknowledgement>
</ns1:CommunicationResponse>
</ns1:Output>
</xsl:variable>
<xsl:apply-templates select="exsl:node-set($result)/*" mode="step2" />
</xsl:template>
<xsl:template match="*[not(normalize-space())]" mode="step2" />
<xsl:template match="#* | node()" mode="step2">
<xsl:copy>
<xsl:apply-templates select="#* | node()" mode="step2" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
http://xsltransform.net/93wkLHW
If you take a top-down aproach with literal result elements you are always going to get that element in the output. Your only choice then is to chain two transformations or use a two pass transformation.
The XPath expression to know whether the current node is empty (true) or not (false) is:
"not(node())"
For example, this input document
<?xml version="1.0" encoding="UTF-8" ?>
<updateDocumentStatusResponse xmlns="http://xmlns.be/CommgrService_Message/v001">
<Acknowledgement>
<Result>SUCCESS</Result>
<ErrorCode>ErrorCode1375</ErrorCode>
<ErrorDescription></ErrorDescription>
</Acknowledgement>
</updateDocumentStatusResponse>
With this transformation
<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="*[not(node())]"/>
</xsl:stylesheet>
Output
<updateDocumentStatusResponse xmlns="http://xmlns.be/CommgrService_Message/v001">
<Acknowledgement>
<Result>SUCCESS</Result>
<ErrorCode>ErrorCode1375</ErrorCode>
</Acknowledgement>
</updateDocumentStatusResponse>
Edit
The previus stylesheet is general. If you want to target specific elements, you need to match those elements with the pattern in the template. Example:
<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="ErrorDescription[not(node())]"/>
</xsl:stylesheet>

XSLT code to remove xml tag

I have an incoming XML like below: I need to remove the <shoeboxImage> tag from the incoming below XML.
Incoming XML Input:
<attachReceipt>
<baseMessage>
<returnCode>200</returnCode>
</baseMessage>
<payload>
<returnCode>0</returnCode>
<shoeboxItem>
<shoeboxImageCount>2</shoeboxImageCount>
<shoeboxImages>
<shoeboxImage>
<name>receiptImage.jpg</name>
</shoeboxImage>
<shoeboxImage>
<name>receiptImage.jpg</name>
</shoeboxImage>
</shoeboxImages>
</shoeboxItem>
</payload>
</attachReceipt>
Expected Output:
<attachReceipt>
<baseMessage>
<returnCode>200</returnCode>
</baseMessage>
<payload>
<returnCode>0</returnCode>
<shoeboxItem>
<shoeboxImageCount>2</shoeboxImageCount>
<shoeboxImages>
<name>receiptImage.jpg</name>
<name>receiptImage.jpg</name>
</shoeboxImages>
</shoeboxItem>
</payload>
</attachReceipt>
Need some xslt code snippet to do this.
I don't have the necessary software installed to actually test this, but this should work:
<xsl:template match="shoeboxImage">
<xsl:apply-templates select="*|text()"/>
</xsl:template>
The idea is that when a shoeboxImage element is encountered, it generates nothing for the element itself, and just continues with its children.
You need to have an identity template and a template that will remove the element shoeboxImage but will retain its descendants.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<!-- identity template -->
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<!-- template override for the element shoeboxImage -->
<xsl:template match="shoeboxImage">
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>

Adding new xml element and changing the value of an element within the same parent element

I need to make certain modifications to my XML input, depending on certain conditions. I am using XSLT 1.0.
the value of the message_type element (child element of m_cotrol) should be changed
A new element message_status should be added (as a child of the m_control element).
These changes are reflected in the expected output XML. With my current XSLT code, I am only able to achieve the second requirement.
Input XML:
<?xml version="1.0"?>
<message xmlns="http://www.origoservices.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<m_control>
<control_timestamp>2013-04-12T09:24:38.902</control_timestamp>
<message_id>a50ec030-72ab</message_id>
<retry_number>0</retry_number>
<message_type>Request</message_type>
<message_version>test.XSD</message_version>
<expected_response_type>synchronous</expected_response_type>
<initiator_id>FST</initiator_id>
<initiator_orchestration_id>1637280</initiator_orchestration_id>
<responder_id>mycomp</responder_id>
</m_control>
<m_content>
<b_control>
<service_provider_reference_number>650971</service_provider_reference_number>
<intermediary_case_reference_number>Sample1</intermediary_case_reference_number>
<quote_type>Comparison</quote_type>
<quote_or_print>Print</quote_or_print>
<message_version_number>3.7</message_version_number>
<submission_date>0001-04-12</submission_date>
</b_control>
</m_content>
</message>
Expected Output:
<message xmlns="http://www.origoservices.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<m_control>
<control_timestamp>2013-04-12T09:24:38.902</control_timestamp>
<message_id>a50ec030-72ab</message_id>
<retry_number>0</retry_number>
<message_type>Response</message_type>
<message_version>test.XSD</message_version>
<expected_response_type>synchronous</expected_response_type>
<initiator_id>FST</initiator_id>
<initiator_orchestration_id>1637280</initiator_orchestration_id>
<responder_id>mycomp</responder_id>
<message_status>User not allowed access</message_status>
</m_control>
<m_content>
<b_control>
<service_provider_reference_number>650971</service_provider_reference_number>
<intermediary_case_reference_number>Sample1</intermediary_case_reference_number>
<quote_type>Comparison</quote_type>
<quote_or_print>Print</quote_or_print>
<message_version_number>3.7</message_version_number>
<submission_date>0001-04-12</submission_date>
<quote_response_status>Error</quote_response_status>
<quote_error_note>
<reason>[Error] Check if the User has access to the requested service</reason>
</quote_error_note>
</b_control>
</m_content>
</message>
XSLT code: Based on the value of DataPower variable (var://service/error-message), I need the expected output.
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dp="http://www.datapower.com/extensions" version="1.0" extension-element-prefixes="dp" exclude-result-prefixes="dp">
<xsl:output method="xml" encoding="UTF-8"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//*[contains(name(),'m_control')]">
<xsl:choose>
<xsl:when test="dp:variable('var://service/error-message') = 'not present'">
<m_control xmlns="http://www.origoservices.com">
<xsl:apply-templates select="#* | *"/>
<message_status>User not recognized</message_status>
</m_control>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template match="//*[contains(name(),'b_control')]">
<xsl:choose>
<xsl:when test="dp:variable('var://service/error-subcode')='0x01d30002'">
<b_control xmlns="http://www.origoservices.com">
<xsl:apply-templates select="#* | *"/>
<quote_response_status>Error</quote_response_status>
<quote_error_note>
<reason>[Error] Check if the User has access to the requested service</reason>
</quote_error_note>
</b_control>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
The following stylesheet meets both of your requirements. It does a common identity transform (which your XSLT does, too) with exceptions.
Note that I have not taken into consideration any changes that are performed by your stylesheet but not listed as a requirement (i.e. changing quote_error_note and quote_response_status).
This line:
<xsl:template match="text()[parent::ori:message_type]">
meets your first requirement, the one you were unable to code. It matches the text content of message_type and outputs "Response" instead.
But this solution differs from yours in another way: it does not match elements along the lines of:
<xsl:template match="//*[contains(name(),'m_control')]">
Rather, their correct namespace is identified:
<xsl:template match="ori:m_control">
Now, what's the difference? Your way of describing the template match allows elements of any namespace to be matched. This might not be a problem in your case (no conflicting namespaces) but it could be one in general.
Full stylesheet
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ori="http://www.origoservices.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
exclude-result-prefixes="ori xsi">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ori:m_control">
<xsl:copy>
<xsl:apply-templates/>
<message_status>
<xsl:text>User not allowed access</xsl:text>
</message_status>
</xsl:copy>
</xsl:template>
<xsl:template match="text()[parent::ori:message_type]">
<xsl:text>Response</xsl:text>
</xsl:template>
</xsl:stylesheet>

xslt: move all siblings inside the first one

I've searched through similar questions, but couldn't make any of the suggestions to work. I have the following xml I need to modify it
<XDB>
<ROOT>
<KEY><ID>12345</ID><DATE>5/10/2011</DATE></KEY>
<PERSONAL><ID>1</ID><INFO><LASTNAME>Smith</LASTNAME>...</INFO></PERSONAL>
<CONTACT><ID>1</ID><EMAIL>asmith#yahoo.com</EMAIL>...</CONTACT>
</ROOT>
<ROOT>
<KEY><ID>98765</ID><DATE>5/10/2013</DATE></KEY>
<CONTACT><ID>2</ID><EMAIL>psmithton#yahoo.com</EMAIL>...</CONTACT>
</ROOT>
...
</XDB>
And it needs to look like this:
<XDB>
<ROOT>
<KEY><ID>12345</ID><DATE>5/10/2011</DATE>
<PERSONAL><ID>1</ID><INFO><LASTNAME>Smith</LASTNAME>...</INFO></PERSONAL>
<CONTACT><ID>1</ID><EMAIL>asmith#yahoo.com</EMAIL>...</CONTACT>
</KEY>
</ROOT>
<ROOT>
<KEY><ID>98765</ID><DATE>5/10/2013</DATE>
<CONTACT><ID>2</ID><EMAIL>psmithton#yahoo.com</EMAIL>...</CONTACT>
</KEY>
</ROOT>
...
</XDB>
I need to make 2...n siblings as children of the first 'key' sibling. Essentially, i need to remove the closing < /KEY> and put it before the closing < /ROOT>. I would appreciate your help.
Thanks.
Following xslt based on Identity transform could make this job
<?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"/>
<!-- Copy everything you find... -->
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*" />
</xsl:copy>
</xsl:template>
<!-- ... but if you find first element inside ROOT ... -->
<xsl:template match="ROOT/node()[1]">
<xsl:copy>
<xsl:apply-templates select="node()|#*" />
<!-- ... copy its sibling into it ... -->
<xsl:copy-of select="following-sibling::*" />
</xsl:copy>
</xsl:template>
<!-- ignore other elements inside ROOT element since they are copied in template matching first element -->
<xsl:template match="ROOT/node()[position() > 1]" />
</xsl:stylesheet>