0

this might be a simple question but I just started with xslt and i cant get it to work.

Basically I got an xml with this format coming in:

<?xml version="1.0" encoding="UTF-8"?> 
<FileXML xmlns:vi="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/XSL/Transform"> 
    <vi:Branch> 
        <vi:Identifier>81388</vi:Identifier> 
        <vi:Name>Union Square Limited</vi:Name> 
        <vi:BranchInformation> 
            <vi:BranchInformation> 
                <vi:Employees>3</vi:Employees> 
            </vi:BranchInformation> 
        </vi:BranchInformation> 
    </vi:Branch> 
</FileXML> 

What I am trying to achieve is an output like:

<?xml version="1.0" encoding="UTF-8"?> 
<FileXML xmlns:vi="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/XSL/Transform"> 
<vi:Branch> 
    <vi:Identifier>81388-1</vi:Identifier> 
    <vi:Name>Union Square Limited</vi:Name> 
    <vi:BranchInformation> 
        <vi:BranchInformation> 
            <vi:Employees>1</vi:Employees> 
        </vi:BranchInformation> 
    </vi:BranchInformation> 
</vi:Branch> 
<vi:Branch> 
    <vi:Identifier>81388-2</vi:Identifier> 
    <vi:Name>Union Square Limited</vi:Name> 
    <vi:BranchInformation> 
        <vi:BranchInformation> 
            <vi:Employees>1</vi:Employees> 
        </vi:BranchInformation> 
    </vi:BranchInformation> 
</vi:Branch> 
<vi:Branch> 
    <vi:Identifier>81388-3</vi:Identifier> 
   <vi:Name>Union Square Limited</vi:Name> 
    <vi:BranchInformation> 
        <vi:BranchInformation> 
            <vi:Employees>1</vi:Employees> 
        </vi:BranchInformation> 
    </vi:BranchInformation> 
</vi:Branch> 
</FileXML> 

This means it should read the amount of employees (=3) in the source xml and therefore create three Branch elements with all the original data but assign a unique Identifier. I think I can manage to change the Employees to have the value 1 afterwards but the rest is totally above my current skills.

Any thoughts or ideas are more than welcome! Thanks!

  • May I ask *why* would you want to do this? In general, one would want to *eliminate* redundant repetition of data, not *create* it. – michael.hor257k Dec 30 '13 at 13:33
  • Why is the input data using the namespace `http://www.w3.org/1999/XSL/Transform` which is the namespace of the W3C XSLT language? And speaking about the language, which version do you want to use, can you use version 2.0 which has the XPath `to` operator? – Martin Honnen Dec 30 '13 at 13:35

1 Answers1

1

The following XSLT stylesheet does what you need. It uses XSLT 2.0 since you did not say what version is at your disposal.

As long as the branch has only 1 employee, it performs a common identity transform. If this is not the case, a named template make-branch is called, that recursively generates vi:Branch elements for all employees.

<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:vi="http://www.vi.org/vi">

<xsl:output method="xml" indent="yes"/>

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

<xsl:template match="vi:Branch[number(vi:BranchInformation/vi:BranchInformation/vi:Employees) gt 1]">
  <xsl:call-template name="make-branch"/>
</xsl:template>

<xsl:template name="make-branch">
  <xsl:param name="emp" select="1"/>

  <vi:Branch>
     <vi:Identifier>
        <xsl:value-of select="concat(vi:Identifier,'-',$emp)"/>
     </vi:Identifier>
     <xsl:copy-of select="vi:Name"/>
     <vi:BranchInformation>
        <vi:Employees>1</vi:Employees>
     </vi:BranchInformation>
  </vi:Branch>

  <xsl:choose>
     <xsl:when test="$emp lt number(vi:BranchInformation/vi:BranchInformation/vi:Employees)">
        <xsl:call-template name="make-branch">
           <xsl:with-param name="emp" select="$emp + 1"/>
        </xsl:call-template>
     </xsl:when>
     <xsl:otherwise/>
  </xsl:choose>
</xsl:template>

</xsl:stylesheet>

Applied on the input as follows. It is slightly different from yours, as you can see, I have changed the namespace declaration of xmlns:vi.

<?xml version="1.0" encoding="UTF-8"?> 
<FileXML  xmlns:vi="http://www.vi.org/vi" xmlns="http://www.w3.org/1999/XSL/Transform"> 
 <vi:Branch> 
    <vi:Identifier>81388</vi:Identifier> 
    <vi:Name>Union Square Limited</vi:Name> 
    <vi:BranchInformation> 
        <vi:BranchInformation> 
            <vi:Employees>3</vi:Employees> 
        </vi:BranchInformation> 
    </vi:BranchInformation> 
 </vi:Branch> 
</FileXML>

Gives the following output, I have eliminated a redundant vi:BranchInformation element:

<?xml version="1.0" encoding="UTF-8"?>
<FileXML xmlns:vi="http://www.vi.org/vi" xmlns="http://www.w3.org/1999/XSL/Transform"> 
 <vi:Branch>
  <vi:Identifier>81388-1</vi:Identifier>
  <vi:Name>Union Square Limited</vi:Name>
  <vi:BranchInformation>
     <vi:Employees>1</vi:Employees>
  </vi:BranchInformation>
 </vi:Branch>
 <vi:Branch>
  <vi:Identifier>81388-2</vi:Identifier>
  <vi:Name>Union Square Limited</vi:Name>
  <vi:BranchInformation>
     <vi:Employees>1</vi:Employees>
  </vi:BranchInformation>
 </vi:Branch>
 <vi:Branch>
  <vi:Identifier>81388-3</vi:Identifier>
  <vi:Name>Union Square Limited</vi:Name>
  <vi:BranchInformation>
     <vi:Employees>1</vi:Employees>
  </vi:BranchInformation>
 </vi:Branch> 
</FileXML>

However, it is doubtful whether this transformation actually helps structuring your data. Perhaps, it is rather detrimental to that.

Mathias Müller
  • 22,203
  • 13
  • 58
  • 75
  • Great stuff. Thank you so much. I hope I can learn how to do this by myself. :) Quick question. Why cant I change the namespace for vi to anything else? If I do so the result file will just be the source file again. – user3146479 Dec 30 '13 at 14:05
  • The explanation depends on _where_ you "change the namespace", in the input XML or in the XSLT stylesheet? Perhaps I have answered your question elsewhere already: http://stackoverflow.com/questions/20679790/need-of-namespace-in-xml/20680122#20680122. – Mathias Müller Dec 30 '13 at 14:38
  • argh, thanks Mathias. I am such an idiot. Just changed the namespace in the stylesheet. Works fine now. ;) Just noticed the " gt 1]" in the template-match. What is it used for? – user3146479 Dec 30 '13 at 14:44
  • Now, this is really something you could find out yourself - simply google it. But since I'm writing anyway: it means "greater than" and performs a comparison. – Mathias Müller Dec 30 '13 at 14:46
  • I shouldnt fall into the habit and get too lazy. You are absolutely right! Thanks for your answer and patience! :) – user3146479 Dec 30 '13 at 14:53