0
votes

This is an XML document I would like to transform:

<?xml version="1.0" encoding="utf-8"?>
<batchResponse>
  <searchResponse>
    <searchResultEntry dn="uid=Massan Jill">
      <attr name="cn">
        <value>Massan, Jill</value>
      </attr>
      <attr name="userAccount">
        <value>ABC1234567</value>
        <value>DEF1234567</value>
      </attr>
    </searchResultEntry>
  </searchResponse>
</batchResponse>

This is the xslt I created for Transformation:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <entry>
      <xsl:for-each select="batchResponse/searchResponse/searchResultEntry">
        <xsl:if test="@dn!='' and contains(@dn, 'uid=')">                 
          <import>      
            <cn>
              <xsl:value-of select="attr[@name='cn']/value"/>
            </cn>
            <userAccount>
              <xsl:value-of select="attr[@name='userAccount']/value"/>
            </userAccount>
          </import>    
        </xsl:if>
      </xsl:for-each>
    </entry>
  </xsl:template>
</xsl:stylesheet>

And this is the transformed XML:

<?xml version="1.0" encoding="UTF-8"?>
<entry>
   <import>
      <cn>Massan, Jill</cn>
      <userAccount>ABC1234567</userAccount>
   </import>
</entry>

My Problem is, that the original XML data contains several values for "userAccount" and that the transformed XML should reflect this by unfolding such data to multiple import-entries like this:

<?xml version="1.0" encoding="UTF-8"?>
<entry>
   <import>
      <cn>Massan, Jill</cn>
      <userAccount>ABC1234567</userAccount>
   </import>
   <import>
     <cn>Massan, Jill</cn>
     <userAccount>DEF1234567</userAccount>
   </import>
</entry>

Is this even possible with xslt and if so, how?

1

1 Answers

1
votes

You can use xsl:for-each to select each "user account" entry, and then create an import record for each one of this

Try this XSLT

<xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" />
  <xsl:template match="/">
    <entry>
      <xsl:for-each select="batchResponse/searchResponse/searchResultEntry">
        <xsl:if test="@dn!='' and contains(@dn, 'uid=')">                 
          <xsl:for-each select="attr[@name='userAccount']/value">
          <import>      
            <cn>
              <xsl:value-of select="../../attr[@name='cn']/value"/>
            </cn>
            <userAccount>
              <xsl:value-of select="."/>
            </userAccount>
          </import>    
          </xsl:for-each>
        </xsl:if>
      </xsl:for-each>
    </entry>
  </xsl:template>
</xsl:stylesheet>

Note the expression <xsl:value-of select="../../attr[@name='cn']/value"/> to get the user name. This is because you are positioned on the value element, so you need to go back up the hierarchy to get the user name (.. means get the parent of the current node).

Actually, you can combine the two xsl:for-each statements, and the xsl:if into one, to simplify things. Try this XSLT too

<xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" />
  <xsl:template match="/">
    <entry>
      <xsl:for-each select="batchResponse/searchResponse/searchResultEntry[@dn!='' and contains(@dn, 'uid=')]/attr[@name='userAccount']/value">
      <import>      
        <cn>
          <xsl:value-of select="../../attr[@name='cn']/value"/>
        </cn>
        <userAccount>
          <xsl:value-of select="."/>
        </userAccount>
      </import>    
      </xsl:for-each>
    </entry>
  </xsl:template>
</xsl:stylesheet>