Reputation: 225
My requirement is to remove the namespace declaration from the the input xml using xslt, if certain condition is true.
I have went through various forums in stackoverflow, after that I had managed to build up an xsl, but it still is not working. I am pretty new to xsl and hence need an help here to achieve this.
input xml (Namespace declaration is appearing)
<?xml version="1.0"?>
<message xmlns="http://www.origoservices.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xsi:schemaLocation="http://www.origoservices.com CEBondRealTimeValuationResponse.XSD">
<m_control>
<control_timestamp>2015-11-18T12:15:00</control_timestamp>
<message_id>428f7945-a3d8-49f8-ada3-b6e898ace9fe</message_id>
<retry_number>0</retry_number>
<message_type>test</message_type>
<message_version>test</message_version>
<message_status>Success</message_status>
<expected_response_type>synchronous</expected_response_type>
<initiator_id>Testing</initiator_id>
<responder_id>Test-comp</responder_id>
</m_control>
<m_content>
<b_control>
<contract_enquiry_reference/>
<enquiry_response_status>Error</enquiry_response_status>
<enquiry_error_note code="1005" sequence_number="1">
<short_description>Contract not found.</short_description>
</enquiry_error_note>
</b_control>
<intermediary/>
<request_scope>
<valuation_request type="Current"/>
<valuation_request type="Surrender"/>
<fund_breakdown_request>
<detailed_breakdown_ind>Yes</detailed_breakdown_ind>
</fund_breakdown_request>
</request_scope>
<contract>
<contract_reference_number>20015</contract_reference_number>
</contract>
</m_content>
</message>
Expected output: (Should be without http://www.origoservices.com
and other namespace declaration must be preserved )
<?xml version="1.0" encoding="UTF-8"?>
<message xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xsi:schemaLocation="http://www.origoservices.com CEBondRealTimeValuationResponse.XSD">
<m_control>
<control_timestamp>2015-11-18T12:15:00</control_timestamp>
<message_id>428f7945-a3d8-49f8-ada3-b6e898ace9fe</message_id>
<retry_number>0</retry_number>
<message_type>test</message_type>
<message_version>test</message_version>
<message_status>Success</message_status>
<expected_response_type>synchronous</expected_response_type>
<initiator_id>Testing</initiator_id>
<responder_id>Test-comp</responder_id>
</m_control>
<m_content>
<b_control>
<contract_enquiry_reference/>
<enquiry_response_status>Error</enquiry_response_status>
<enquiry_error_note code="1005" sequence_number="1">
<short_description>Contract not found.</short_description>
</enquiry_error_note>
</b_control>
<intermediary/>
<request_scope>
<valuation_request type="Current"/>
<valuation_request type="Surrender"/>
<fund_breakdown_request>
<detailed_breakdown_ind>Yes</detailed_breakdown_ind>
</fund_breakdown_request>
</request_scope>
<contract>
<contract_reference_number>20015</contract_reference_number>
</contract>
</m_content>
</message>
I have tried below xslt:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dp="http://www.datapower.com/extensions" extension-element-prefixes="dp" exclude-result-prefixes="dp">
<xsl:output method="xml" indent="yes" version="1.0" />
<xsl:variable name="origo-svc-augmented" select="'Y'"/>
<xsl:variable name="origo-svc-ns" select="'http://www.origoservices.com'" />
<xsl:template match="*">
<xsl:variable name="namespace" select="namespace-uri(.)" />
<xsl:choose>
<!--
xsl:when test="$namespace = ''
or ($origo-svc-augmented='Y' and $namespace=$origo-svc-ns)"
-->
<xsl:when test="$origo-svc-augmented = 'Y'">
<xsl:message dp:type="business-log" dp:priority="info">Namespace was augmented in the request rule</xsl:message>
<!-- Note: If we use "local-name()" instead of "name()" in below statement, then namespace prefixes will not be preserved. Using name(), will preserve the namespace prefixes
-->
<!-- xsl:element name="{name()} namespace="{$namespace}"
-->
<xsl:element name="{name()}">
<xsl:copy-of select="namespace::*[not(namespace-uri()=$origo-svc-ns)]" />
<xsl:apply-templates select="@*|node()|comment()|processing-instruction()|text()" />
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:element name="{name()}" namespace="{$namespace}">
<xsl:copy-of select="namespace::*" />
<xsl:apply-templates select="@*|node()|comment()|processing-instruction()|text()" />
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="@*|comment()|processing-instruction()|text()">
<xsl:copy>
<xsl:apply-templates select="@*|node()|comment()|processing-instruction()|text()" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
UPDATE
I have tried to combine both the answers and able to find the solution for this. Please find the working XSLT below.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dp="http://www.datapower.com/extensions" extension-element-prefixes="dp" exclude-result-prefixes="dp">
<xsl:output method="xml" indent="yes" version="1.0"/>
<xsl:variable name="origo-svc-augmented" select="'Y'"/>
<xsl:variable name="origo-svc-ns" select="'http://www.origoservices.com'"/>
<xsl:template match="*">
<xsl:variable name="namespace" select="namespace-uri(.)"/>
<xsl:choose>
<xsl:when test="($origo-svc-augmented = 'Y') and (namespace-uri() = $origo-svc-ns)">
<xsl:message dp:type="business-log" dp:priority="info">Namespace was augmented in the request rule</xsl:message>
<xsl:element name="{local-name()}">
<xsl:copy-of select="namespace::*[.!='http://www.origoservices.com']"/>
<xsl:apply-templates
select="@* | node() | comment() | processing-instruction() | text()"/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:element name="{name()}" namespace="{$namespace}">
<xsl:copy-of select="namespace::*"/>
<xsl:apply-templates
select="@* | node() | comment() | processing-instruction() | text()"/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Upvotes: 0
Views: 2000
Reputation: 225
have tried to combine both the answers and able to find the solution for this. Please find the working XSLT below.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dp="http://www.datapower.com/extensions" extension-element-prefixes="dp" exclude-result-prefixes="dp">
<xsl:output method="xml" indent="yes" version="1.0"/>
<xsl:variable name="origo-svc-augmented" select="'Y'"/>
<xsl:variable name="origo-svc-ns" select="'http://www.origoservices.com'"/>
<xsl:template match="*">
<xsl:variable name="namespace" select="namespace-uri(.)"/>
<xsl:choose>
<xsl:when test="($origo-svc-augmented = 'Y') and (namespace-uri() = $origo-svc-ns)">
<xsl:message dp:type="business-log" dp:priority="info">Namespace was augmented in the request rule</xsl:message>
<xsl:element name="{local-name()}">
<xsl:copy-of select="namespace::*[.!='http://www.origoservices.com']"/>
<xsl:apply-templates
select="@* | node() | comment() | processing-instruction() | text()"/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:element name="{name()}" namespace="{$namespace}">
<xsl:copy-of select="namespace::*"/>
<xsl:apply-templates
select="@* | node() | comment() | processing-instruction() | text()"/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Upvotes: 0
Reputation: 116993
If I am guessing correctly, you want to do something like:
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="*"/>
<xsl:param name="no-namespace" select="false()"/>
<xsl:template match="*">
<xsl:choose>
<xsl:when test="$no-namespace">
<xsl:element name="{local-name()}">
<xsl:copy-of select="namespace::*[.!='http://www.origoservices.com']"/>
<xsl:copy-of select="@*"/>
<xsl:apply-templates/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:copy-of select="namespace::*[.!='http://www.origoservices.com']"/>
<xsl:copy-of select="@*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
When the no-namespace
parameter is true, the result, applied to your input example, will probably (see note below) be:
<?xml version="1.0" encoding="UTF-8"?>
<message xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xsi:schemaLocation="http://www.origoservices.com CEBondRealTimeValuationResponse.XSD">
<m_control>
<control_timestamp>2015-11-18T12:15:00</control_timestamp>
<message_id>428f7945-a3d8-49f8-ada3-b6e898ace9fe</message_id>
<retry_number>0</retry_number>
<message_type>test</message_type>
<message_version>test</message_version>
<message_status>Success</message_status>
<expected_response_type>synchronous</expected_response_type>
<initiator_id>Testing</initiator_id>
<responder_id>Test-comp</responder_id>
</m_control>
<m_content>
<b_control>
<contract_enquiry_reference/>
<enquiry_response_status>Error</enquiry_response_status>
<enquiry_error_note code="1005" sequence_number="1">
<short_description>Contract not found.</short_description>
</enquiry_error_note>
</b_control>
<intermediary/>
<request_scope>
<valuation_request type="Current"/>
<valuation_request type="Surrender"/>
<fund_breakdown_request>
<detailed_breakdown_ind>Yes</detailed_breakdown_ind>
</fund_breakdown_request>
</request_scope>
<contract>
<contract_reference_number>20015</contract_reference_number>
</contract>
</m_content>
</message>
If the no-namespace
parameter is false, the result will be an identical copy of the input.
Note:
The actual result may wary according to the specific XSLT processor being used. The namespace declaration xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
is not used anywhere, and is therefore redundant. You cannot really force an XSLT 1.0 processor to output a redundant namespace declaration. The above result is correct for Saxon 6.5 and libxslt - but Xalan will ignore the instruction to copy namespaces and the redundant namespace will be suppressed.
Upvotes: 1
Reputation: 163322
It's important to understand that in terms of the XDM data model, what you are doing is not removing a namespace, but rather changing the name of the element.
Unless you have QNames (or namespace prefixes) appearing within the content of your elements or attributes (as opposed to their names), you shouldn't need to worry about using the namespace axis or generating namespace nodes. Just generate elements and attributes with the correct names (by which I mean namespace URI plus local name) and the namespace declarations will take care of themselves.
The xsl:copy
instruction, when applied to an element, copies the whole name (namespace URI plus local name) of the element. If you want to generate an element with the same local name but in a different namespace, or in no namespace, you need to use xsl:element name="{local-name()}"
You've had plenty of responses suggesting what code you need to write, but I thought it would be helpful to add a word on the underlying principles.
Upvotes: 2
Reputation: 7905
Assuming you only want to remove the namespace related to the http://www.origoservices.com
URI, I would change the condition a namespace removal to:
<xsl:when test="($origo-svc-augmented = 'Y') and (namespace-uri() = $origo-svc-ns)">
and then output the element like so, to avoid copying the namespaces:
<xsl:element name="{local-name()}">
Copying the namespace nodes with <xsl:copy-of select="namespace::*[not(namespace-uri() = $origo-svc-ns)]"/>
become useless, you can drop it.
Then you end up with the following template:
<xsl:template match="*">
<xsl:variable name="namespace" select="namespace-uri(.)"/>
<xsl:choose>
<xsl:when test="($origo-svc-augmented = 'Y') and (namespace-uri() = $origo-svc-ns)">
<xsl:message dp:type="business-log" dp:priority="info">Namespace was augmented in the request rule</xsl:message>
<xsl:element name="{local-name()}">
<xsl:apply-templates
select="@* | node() | comment() | processing-instruction() | text()"/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:element name="{name()}" namespace="{$namespace}">
<xsl:copy-of select="namespace::*"/>
<xsl:apply-templates
select="@* | node() | comment() | processing-instruction() | text()"/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
This is the resulting XML obtained:
<?xml version="1.0" encoding="UTF-8"?>
<message xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.origoservices.com CEBondRealTimeValuationResponse.XSD">
<m_control>
<control_timestamp>2015-11-18T12:15:00</control_timestamp>
<message_id>428f7945-a3d8-49f8-ada3-b6e898ace9fe</message_id>
<retry_number>0</retry_number>
<message_type>test</message_type>
<message_version>test</message_version>
<message_status>Success</message_status>
<expected_response_type>synchronous</expected_response_type>
<initiator_id>Testing</initiator_id>
<responder_id>Test-comp</responder_id>
</m_control>
<m_content>
<b_control>
<contract_enquiry_reference/>
<enquiry_response_status>Error</enquiry_response_status>
<enquiry_error_note code="1005" sequence_number="1">
<short_description>Contract not found.</short_description>
</enquiry_error_note>
</b_control>
<intermediary/>
<request_scope>
<valuation_request type="Current"/>
<valuation_request type="Surrender"/>
<fund_breakdown_request>
<detailed_breakdown_ind>Yes</detailed_breakdown_ind>
</fund_breakdown_request>
</request_scope>
<contract>
<contract_reference_number>20015</contract_reference_number>
</contract>
</m_content>
</message>
Since the namespace xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
is never used in your input XML document, it won't be output.
Upvotes: 0