Tutorial :Copy the attributes in XSLT



Question:

Now I have an XML file as below:

<DM Name="A DM">     <DV  id="SQL:Select something from db" Name="DV 1">       <Sample aid="SQL:Select something from db" />     </DV>     <DV  id="SQL:Select something from db" Name="DV 2">       <Sample aid="SQL:Select something from db" name ="DC">         good       </Sample>     </DV>   </DM>   

I want to use an XSLT to transform it, there is a parameter in this tamplet to determine which DV should be transformed: if the parameter($dvIndex = 0), then just keep all the elements and attributes, just transform the attriform the attritributes with the value started with "SQL:", if ($dvindext > 0), just transform the specific DV,(remove other DV). Now I write the XSLT as below, but it miss the DM's attributes, I don't know how to copy DM's attributes. I donot know if there is better solution. XML File:

<?xml version="1.0" encoding="utf-8"?>  <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"      xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"      xmlns:user="urn:my-scripts"  >    <xsl:output method="xml" indent="yes"/>    <msxsl:script language="C#" implements-prefix="user">      <![CDATA[       public string UpperCase(string value){        return value.ToUpper();       }        ]]>    </msxsl:script>      <xsl:param name="dvIndex" select="2" />      <xsl:template match="DM" >      <xsl:copy>        <xsl:choose>          <xsl:when test="$dvIndex > 0">            <xsl:apply-templates select="DV[$dvIndex]"/>          </xsl:when>          <xsl:otherwise>            <xsl:copy>              <xsl:apply-templates select="@*|node()"/>            </xsl:copy>          </xsl:otherwise>        </xsl:choose>      </xsl:copy>    </xsl:template>      <xsl:template match="@*|node()">      <xsl:copy>        <xsl:apply-templates select="@*|node()"/>      </xsl:copy>    </xsl:template>      <!--[starts-with(translate(substring(.,1,4),'SQL:','sql:'),'sql:')]-->    <xsl:template match="@*[user:UpperCase(substring(.,1,4))='SQL:']">      <xsl:attribute name="{name()}">        <xsl:value-of select="'parsedSQL'"/>      </xsl:attribute>    </xsl:template>  </xsl:stylesheet>  

this question is also related to my question 2# (How to only convert an XML file's attribute using XSLT, and leave the other content?)

Thanks very much!


Solution:1

This stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">      <xsl:output method="xml" indent="yes"/>      <xsl:param name="dvIndex" select="2" />      <xsl:template match="DM" >          <xsl:copy>              <xsl:apply-templates select="@*|DV[$dvIndex]"/>          </xsl:copy>      </xsl:template>      <xsl:template match="@*|node()">          <xsl:copy>              <xsl:apply-templates select="@*|node()"/>          </xsl:copy>      </xsl:template>      <xsl:template match="@*[starts-with(translate(substring(.,1,4),'SQL:','sql:'),'sql:')]">          <xsl:attribute name="{name()}">              <xsl:value-of select="'parsedSQL'"/>          </xsl:attribute>      </xsl:template>  </xsl:stylesheet>  

Result:

<DM Name="A DM">  <DV id="parsedSQL" Name="DV 2">  <Sample aid="parsedSQL" name="DC">        good      </Sample>  </DV>  </DM>  

With param dvIndex in 0:

<DM Name="A DM"></DM>  

Note: Avoid scripting: it's not standar, it'll force to load script engine every time is used.

EDIT: If you want to process every DV when $dvIndex is 0, then this stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">      <xsl:output method="xml" indent="yes"/>      <xsl:param name="dvIndex" select="2" />      <xsl:template match="DM" >          <xsl:copy>              <xsl:apply-templates select="@*|DV[$dvIndex]|DV[not($dvIndex)]"/>          </xsl:copy>      </xsl:template>      <xsl:template match="@*|node()">          <xsl:copy>              <xsl:apply-templates select="@*|node()"/>          </xsl:copy>      </xsl:template>      <xsl:template match="@*[starts-with(translate(substring(.,1,4),'SQL:','sql:'),'sql:')]">          <xsl:attribute name="{name()}">              <xsl:value-of select="'parsedSQL'"/>          </xsl:attribute>      </xsl:template>  </xsl:stylesheet>  

With $dvIndex is 0, output:

<DM Name="A DM">  <DV id="parsedSQL" Name="DV 1">  <Sample aid="parsedSQL"></Sample>  </DV>  <DV id="parsedSQL" Name="DV 2">  <Sample aid="parsedSQL" name="DC">        good      </Sample>  </DV>  </DM>  


Solution:2

The following probably does what you need. Note the additional <xsl:apply-templates select="@*" /> to copy the attributes.

<?xml version="1.0" encoding="utf-8"?>  <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"      xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"      xmlns:user="urn:my-scripts">      <xsl:output method="xml" indent="yes"/>    <msxsl:script language="C#" implements-prefix="user">      <![CDATA[       public string UpperCase(string value){        return value.ToUpper();       } ]]>    </msxsl:script>      <xsl:param name="dvIndex" select="0" />      <xsl:template match="DM" >      <xsl:copy>        <xsl:apply-templates select="@*" />        <xsl:choose>          <xsl:when test="$dvIndex > 0">            <xsl:apply-templates select="DV[$dvIndex]"/>          </xsl:when>          <xsl:otherwise>              <xsl:apply-templates select="DV"/>          </xsl:otherwise>        </xsl:choose>      </xsl:copy>    </xsl:template>      <xsl:template match="@*|node()">      <xsl:copy>        <xsl:apply-templates select="@*|node()"/>      </xsl:copy>    </xsl:template>      <!--[starts-with(translate(substring(.,1,4),'SQL:','sql:'),'sql:')]-->    <xsl:template match="@*[user:UpperCase(substring(.,1,4))='SQL:']">      <xsl:attribute name="{name()}">        <xsl:value-of select="'parsedSQL'"/>      </xsl:attribute>    </xsl:template>  </xsl:stylesheet>  

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »