Question

I have the following XML (Much of the data is dummy)

<?xml version="1.0" encoding="UTF-8"?>
<msg xmlns="http://someaddress.com/m1"  xmlns:ds="http://www.w3.org/2000/09/xmldsig#"   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xsi:schemaLocation="http://someaddress/somexsd.xsd">
<header>
    <nodeA>aaaaaaaaaaa</nodeA>
    <nodeB>bbbbbbbb</nodeB>
</header>
<payload>
    <calcnode   xmlns="http://someaddress/nodeC"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xsi:schemaLocation="http://someaddress/somexsd.xsd">
        <somefield>field</somefield>
    </calcnode>
    <ds:Signature>
        <SignedInfo>
            <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
            <SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
            <Reference URI="#kjbn34jkb5j-3k45j-k3jb534jkb534k5">
                <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
                <DigestValue>+se0dfgft9gh8hjuji7ji65ko4ko3ko2</DigestValue>
            </Reference>
        </SignedInfo>
        <SignatureValue>sekfrhsdkjfhsdkjfhksd</SignatureValue>
        <KeyInfo>
            <X509Data>
                <X509Certificate>sdjkfhsdkfhskdf</X509Certificate>
            </X509Data>
        </KeyInfo>
    </ds:Signature>
</payload>
</msg>

And all I want to do is change the name of the msg element (to newmsg) and the default namespace to http://someaddress.com/m2. Everything else should be kept as is. the closest I have been able to get is this xslt

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msg="http://someaddress.com/m1" >

<!-- the identity template -->
<xsl:template match="@* | node()">
    <xsl:copy copy-namespaces="no">
        <xsl:apply-templates select="@* | node()" />
    </xsl:copy>
</xsl:template>

<!-- replace namespace of elements in old namespace -->
<xsl:template match="msg:msg">
  <xsl:element name="newmsg" namespace="http://someaddress.com/m2">
     <xsl:apply-templates select="@* | node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>

I am using xalan for testing and this is the output xml I get when running the above

<?xml version="1.0" encoding="UTF-8"?>
    <newmsg xmlns="http://someaddress.com/m2" xsi:schemaLocation="http://someaddress/somexsd.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<header xmlns="http://someaddress.com/m1" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
    <nodeA>aaaaaaaaaaa</nodeA>
    <nodeB>bbbbbbbb</nodeB>
</header>
<payload xmlns="http://someaddress.com/m1" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
    <calcnode xmlns="http://someaddress/nodeC" xsi:schemaLocation="http://someaddress/somexsd.xsd">
        <somefield>field</somefield>
    </calcnode>
    <ds:Signature>
        <SignedInfo>
            <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
            <SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
            <Reference URI="#kjbn34jkb5j-3k45j-k3jb534jkb534k5">
                <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
                <DigestValue>+se0dfgft9gh8hjuji7ji65ko4ko3ko2</DigestValue>
            </Reference>
        </SignedInfo>
        <SignatureValue>sekfrhsdkjfhsdkjfhksd</SignatureValue>
        <KeyInfo>
            <X509Data>
                <X509Certificate>sdjkfhsdkfhskdf</X509Certificate>
            </X509Data>
        </KeyInfo>
    </ds:Signature>
</payload>
</newmsg>

There are 2 main problems with this:

  1. The ds namespace simply disappears from the output and I don't know why.
  2. The second issue is that it drops the xsi namespace from the calcnode and given that the calcnode is the node used to calculate (and verify) the signature (Which comes below that section) such change would make verification of the signature impossible to my understanding.

I have tried several different iterations of the xslt without much results. Could anybody shed some light in the situation?

Was it helpful?

Solution

This transformation:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:oldDef="http://someaddress.com/m1" exclude-result-prefixes="oldDef">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="*">
  <xsl:element name="{name()}" namespace="{namespace-uri()}">
   <xsl:copy-of select="namespace::*[name()]|@*"/>
   <xsl:apply-templates select="node()"/>
  </xsl:element>
 </xsl:template>

 <xsl:template match="*[namespace-uri()='http://someaddress.com/m1']">
  <xsl:element name="{name()}" namespace="http://someaddress.com/m2">
   <xsl:copy-of select="namespace::*[name()]"/>
   <xsl:copy-of select="@*"/>
   <xsl:apply-templates select="node()"/>
  </xsl:element>
 </xsl:template>

 <xsl:template match="oldDef:msg[true()]">
  <newmsg xmlns="http://someaddress.com/m2">
   <xsl:copy-of select="namespace::*[name()]|@*"/>
   <xsl:apply-templates select="node()"/>
  </newmsg>
 </xsl:template>
</xsl:stylesheet>

when applied on the provided XML document:

<msg xmlns="http://someaddress.com/m1"  xmlns:ds="http://www.w3.org/2000/09/xmldsig#"   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xsi:schemaLocation="http://someaddress/somexsd.xsd">
<header>
    <nodeA>aaaaaaaaaaa</nodeA>
    <nodeB>bbbbbbbb</nodeB>
</header>
<payload>
    <calcnode   xmlns="http://someaddress/nodeC"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   xsi:schemaLocation="http://someaddress/somexsd.xsd">
        <somefield>field</somefield>
    </calcnode>
    <ds:Signature>
        <SignedInfo>
            <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
            <SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
            <Reference URI="#kjbn34jkb5j-3k45j-k3jb534jkb534k5">
                <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
                <DigestValue>+se0dfgft9gh8hjuji7ji65ko4ko3ko2</DigestValue>
            </Reference>
        </SignedInfo>
        <SignatureValue>sekfrhsdkjfhsdkjfhksd</SignatureValue>
        <KeyInfo>
            <X509Data>
                <X509Certificate>sdjkfhsdkfhskdf</X509Certificate>
            </X509Data>
        </KeyInfo>
    </ds:Signature>
</payload>
</msg>

produces the wanted, correct result:

<newmsg xmlns="http://someaddress.com/m2" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://someaddress/somexsd.xsd">
   <header>
      <nodeA>aaaaaaaaaaa</nodeA>
      <nodeB>bbbbbbbb</nodeB>
   </header>
   <payload>
      <calcnode xmlns="http://someaddress/nodeC" xsi:schemaLocation="http://someaddress/somexsd.xsd">
         <somefield>field</somefield>
      </calcnode>
      <ds:Signature>
         <SignedInfo>
            <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
            <SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
            <Reference URI="#kjbn34jkb5j-3k45j-k3jb534jkb534k5">
               <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
               <DigestValue>+se0dfgft9gh8hjuji7ji65ko4ko3ko2</DigestValue>
            </Reference>
         </SignedInfo>
         <SignatureValue>sekfrhsdkjfhsdkjfhksd</SignatureValue>
         <KeyInfo>
            <X509Data>
               <X509Certificate>sdjkfhsdkfhskdf</X509Certificate>
            </X509Data>
         </KeyInfo>
      </ds:Signature>
   </payload>
</newmsg>

OTHER TIPS

Try defining the ds namespace in the <xsl:stylesheet element of your XSLT, though the ds namespace isn't lost, it's just distributed to all the child elements of newmsg. Similarly, the xsi namespace is applied to the root element (newmsg) and therefore will apply to the calcnode as well.

The output appears to be valid, even though some of the namespace declarations have moved.

I've written an article with some information about controlling namespaces that may provide some insight: Transforming XHTML using XSLT identity templates

And all I want to do is change the name of the msg element (to newmsg) and the default namespace to http://someaddress.com/m2. Everything else should be kept as is.

Stylesheet:

<xsl:stylesheet version="2.0" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:msg="http://someaddress.com/m1">

  <xsl:output omit-xml-declaration="yes"/>

  <xsl:template match="@* | node()">
    <xsl:copy copy-namespaces="no">
      <xsl:apply-templates select="@* | node()" />
    </xsl:copy>
  </xsl:template>

  <!-- Process all elements (except 'msg') in the 'msg' namespace -->
  <xsl:template match="msg:*">
    <xsl:element name="{local-name()}" namespace="http://someaddress.com/m2">
      <xsl:apply-templates select="@* | node()"/>
    </xsl:element>
  </xsl:template>

  <!-- Change 'msg' element into 'newmsg' -->
  <xsl:template match="msg:msg">
    <xsl:element name="newmsg" namespace="http://someaddress.com/m2" >
      <!-- Keep "ds" declaration on the root element -->
      <xsl:namespace name="ds" select="'http://www.w3.org/2000/09/xmldsig#'"/>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

When the stylesheet is applied to the XML source, it outputs (using Saxon 9.4):

<newmsg xmlns="http://someaddress.com/m2" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://someaddress/somexsd.xsd">
  <header>
    <nodeA>aaaaaaaaaaa</nodeA>
    <nodeB>bbbbbbbb</nodeB>
  </header>
  <payload>
    <calcnode xmlns="http://someaddress/nodeC" xsi:schemaLocation="http://someaddress/somexsd.xsd">
      <somefield>field</somefield>
    </calcnode>
    <ds:Signature>
      <SignedInfo>
        <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
        <SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
        <Reference URI="#kjbn34jkb5j-3k45j-k3jb534jkb534k5">
          <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
          <DigestValue>+se0dfgft9gh8hjuji7ji65ko4ko3ko2</DigestValue>
        </Reference>
      </SignedInfo>
      <SignatureValue>sekfrhsdkjfhsdkjfhksd</SignatureValue>
      <KeyInfo>
        <X509Data>
          <X509Certificate>sdjkfhsdkfhskdf</X509Certificate>
        </X509Data>
      </KeyInfo>
    </ds:Signature>
  </payload>
</newmsg>

This is not exactly what you want, but it's close. There is still no xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" declaration on the calcnode element, because xsi is already declared on the root element. If this is a problem for the signature processing, I'm not sure how to address that.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top