2

I am trying to convert elements into attributes along with addition of namespace prefix. But I am not able to do both the things in same XSLT.

Source XML:

    <createDocument> 
    <ecm_cmd_doc> 
        <ecm_application_name>preview</ecm_application_name>  
        <ecm_operation> 
            <mode>asynchronous</mode>  
            <name>create</name> 
        </ecm_operation>  
        <doc_in_create> 
            <doc_object_attribute_create> 
                <doc_format>pdf</doc_format>  
                <dctm_folder/>  
                <dctm_object_type>ecm_gbd_check_image_doc</dctm_object_type>  
                <doc_attr> 
                    <attr_name>document_code</attr_name>  
                    <attr_value>9002</attr_value> 
                </doc_attr>                     
                <doc_attr> 
                    <attr_name>bill_customer_identifier</attr_name>  
                    <attr_value>234567898</attr_value> 
                </doc_attr> 
                <file_info> 
                    <URL>1234567890.pdf</URL>  
                    <URI>1234567890.pdf</URI>  
                    <file_in_target>false</file_in_target> 
                </file_info> 
            </doc_object_attribute_create> 
        </doc_in_create> 
    </ecm_cmd_doc> 
</createDocument>    

XSLT Used:

      <xsl:stylesheet env:encodingStyle="" xmlns:p="http://tempuri.org/"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" version="1.0">
      <xsl:output method="xml" indent="yes" omit-xml-declaration="yes" /> 
      <xsl:strip-space elements="*"/> 

      <xsl:template match="/">
      <xsl:apply-templates select="/*"/>  
      </xsl:template>

      <xsl:template match="*">
      <xsl:copy> 
      <xsl:for-each select="mode|doc_format|URL|URI|file_in_target|xmlns|dctm_folder|name|dctm_object_type|attr_value|attr_name">
       <xsl:attribute name="{name()}">
       <xsl:value-of select="."/> 
       </xsl:attribute>
       </xsl:for-each>
       <xsl:apply-templates select="node()[not(self::mode or self::dctm_folder or self::doc_format or self::xmlns or self::URL or self::URI or self::file_in_target or self::name or self::dctm_object_type or self::attr_value or self::attr_name)]" /> 
       </xsl:copy>
       </xsl:template>

       </xsl:stylesheet>

Expected Output:

    <p:createDocument xmlns:p="http://ecm.com/ecm_c_dc">
    <p:ecm_cmd_doc>
    <p:ecm_application_name>preview</p:ecm_application_name>
    <p:ecm_operation mode="asynchronous" name="create"/>
    <p:doc_in_create>
     <p:doc_object_attribute_create doc_format="pdf"
                                  dctm_folder=""
                                  dctm_object_type="ecm_gbd_check_image_doc">
        <p:doc_attr attr_name="document_code" attr_value="9002"/>
        <p:doc_attr attr_name="bill_customer_identifier" attr_value="234567898"/>
        <p:file_info URL="1234567890.pdf" URI="1234567890.pdf" file_in_target="false"/>
     </p:doc_object_attribute_create>
     </p:doc_in_create>
     </p:ecm_cmd_doc>
     </p:createDocument>

Would appreciate any help on this!

1 Answer 1

3

You cannot use xsl:copy when you want to output an element in a different namespace.

Try it this way instead:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:p="http://ecm.com/ecm_c_dc">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="*">
    <xsl:element name="p:{name()}">
        <xsl:apply-templates/>
    </xsl:element>
</xsl:template>

<xsl:template match="mode|doc_format|URL|URI|file_in_target|xmlns|dctm_folder|name|dctm_object_type|attr_value|attr_name">
    <xsl:attribute name="{name()}">
        <xsl:value-of select="."/> 
    </xsl:attribute>
</xsl:template>

</xsl:stylesheet>
Sign up to request clarification or add additional context in comments.

3 Comments

Note @somyasikka: using name="p:{name()}" can result in unexpected errors if the source document contains elements in a namespace (not here), to be safe, use name="p:{local-name()}".
@Abel It is just as "unsafe" as using match="mode|... ". A stylesheet is custom-tailored to the given input and output schemas. If they change, the stylesheet will break.
True, except that name="p:{name()}" will result in XTDE0820 (or the 1.0 equivalent), whereas non-matching patterns simply don't match. But you are right, if the input will never uses namespaces, it won't matter. As an aside, in XSLT 1.0, this error can be ignored, in which case only the content of xsl:element is constructed (as does Saxon 6.5). Other processors raise an error.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.