3

I'm trying to convert the xml data in following format to csv format using xslt.I am right now struck trying to output multivalues for particular custom field. This is my xml data.

<input-xml>
 <add add-value="First Name">
    <value type="string">Newbee</value>
  </add>
   <add add-value="Surname">
    <value  type="string">user1</value>
  </add>
  <add add-value="Title">
    <value type="string">Software,engineer</value>
 </add>
 <add add-value="Title">
    <value type="string">Associate level</value>
  </add>
 <add add-value="Description">
    <value type="string">This user is new to xslt.</value>
  </add>
</input-xml>

Below is the snippet of the xslt code I am using to transform the data.

 <xsl:template match="input-xml">
  <!-- output the fields in order -->
    <xsl:call-template name="output-field">
        <xsl:with-param name="field-value" select="*[(@attr-name = 'First')]/value"/>
    </xsl:call-template>
    .............
    .............
    <xsl:call-template name="output-field">
        <xsl:with-param name="field-value" select="*[(@attr-name = 'Title')]/value"/>
    </xsl:call-template>
 </xsl:template>

 <xsl:template name="output-field">
    <xsl:param name="field-value"/>
    <xsl:choose>
        <xsl:when test="contains($field-value,$delimiter)">
            <!-- if the field value contains a delimiter, then enclose in quotes -->
                             <!--delimiter here is comma (,)-->
            <xsl:text>"</xsl:text>
            <xsl:value-of select="$field-value"/>
            <xsl:text>"</xsl:text>
        </xsl:when>
        <xsl:otherwise>
            <!-- otherwise output it raw -->
            <xsl:value-of select="$field-value"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template

With the above code I'm able to output data as:

Newbee,User1,Software engineer,This user is new to xslt.

This is absolutely fine as long as there are no multiple values. The problem now is there are two value for field 'Title' which will have to enclosed within quotes ("") as below. Expected output csv data:

Newbee,User1,"|Software engineer|,|Associate level|",This user is new to xslt.

I'm not able to figure out what changes i'll have to make above code and how to proceed further.. Can anyone help me out..??

@LarsH your previous reply to question i posted is working fine..I found that for the below xml format,the xslt doesn't quite work the way it is desired.

<input-xml>
 <add add-value="First Name">
    <value type="string">Newbee</value>
  </add>
   <add add-value="Surname">
    <value  type="string">user1</value>

 <add add-value="Title">
    <value type="string">Associate level</value>
    <value type="string">Software,engineer</value>
 </add>

 <add add-value="Description">
    <value type="string">This user is new to xslt.</value>
  </add>
</input-xml>

The output i'm getting is

Newbee,User1,Software engineerAssociate level,This user is new to xslt.

Do i need to write another xslt to be able to handle this xml..? can i modify the existing xslt itself to take care of both xml variants..?

1
  • Farhan, did my answer help you? If not, please let us know what else you need. If it solved your problem, don't forget to check the "accept" green checkmark. Commented Mar 15, 2013 at 1:22

1 Answer 1

1

I would change your output-field template so that instead of taking the value to output, it takes the name of the field (attribute). E.g. pass a field-name parameter instead of field-value. Then you can put your logic about multiple values into that template.

[On second thought, you could do this just as well by passing field value*s* in the way that you already were ... just recognizing that what you are passing is a nodeset, not necessarily just a single value.]

In the output-field template, you can say something like:

<xsl:template name="output-field">
 <xsl:param name="field-name"/>
 <xsl:variable name="field-values" select="*[@attr-name = $field-name]" />
 <xsl:choose>
  <xsl:when test="count($field-values) > 1">
    <xsl:text>"</xsl:text>
      <xsl:for-each select="$field-values">
        <xsl:value-of select="concat('|', ., '|')" />
        <xsl:if test="position() != last()">,</xsl:if>
       </xsl:for-each>
     <xsl:text>"</xsl:text>
   </xsl:when>
   <xsl:when test="contains($field-values[1], $delimiter)">
      ... the rest of your existing template
 </xsl:choose>
</xsl:template>

If you need more help with some of those details, let us know which ones.

Sign up to request clarification or add additional context in comments.

2 Comments

@ LarsH, so the call to template output-field would look something like this <xsl:call-template name="output-field"> <xsl:with-param name="field-name" select="First Name"/> </xsl:call-template> and so on..
Yes, except you'd need to pass the string parameter value with single quotes (inside the double quotes of the select attribute):<xsl:with-param name="field-name" select="'First Name'"/>

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.