Tuesday, October 13, 2009

Mapping several elements to a single element

Frequently we have one block of XML that we want to split to diferent blocks. For instance, when exporting to SQL stored procedures. It is easy to do. Sometimes the opposite happens and the tables are imported from SQL: we have the information divided by several blocks on one XML and we want it grouped.

Let's imagine a simple scenario: one table included the name of a person, the other the professional information. How can we group it to a single element?

We use XSLT.

Supposing that one of the segments has all the keys, the trick is to loop that segment to read the keys and pull the information from all. This way the order of the elements is not important, the association is made by key.

This template compiles the information:

 <xsl:template name="NameValueTemplate">
  <xsl:param name="param1" />
  <xsl:for-each select="//ElementKey">
   <xsl:if test="Id/text()=$param1">
    <xsl:attribute name="Id">xsl:value-of select="Id/text()" /></xsl:attribute>
    <xsl:element name="Name"><xsl:value-of select="Name/text()" /></xsl:element>
   </xsl:if>
  </xsl:for-each>
  <xsl:for-each select="//ElementInfo">
   <xsl:if test="$Id=$param1">
    <xsl:element name="Mail"><xsl:value-of select="Mail/text()" /></xsl:element>
    <xsl:element name="Job"><xsl:value-of select="Job/text()" /></xsl:element>
    <xsl:element name="Phone"><xsl:value-of select="Phone/text()"/></xsl:element>
   </xsl:if>
  </xsl:for-each>
 </xsl:template>


And this is how it is called:

 <xsl:template match="/s0:Root">
  <ns0:Root>
   <xsl:for-each select="//ElementKey">
    <xsl:element name="Element">
     <xsl:call-template name="NameValueTemplate">
      <xsl:with-param name="param1"><xsl:value-of select="Id/text()"/></xsl:with-param>
     </xsl:call-template>
    </xsl:element>
   </xsl:for-each>
  </ns0:Root>
 </xsl:template>



This is it. It includes attributes and elements to include a broad range of situations. More complex cases can be made from this.

No comments: