Re: [xsl] Convert XML elements with extended attributes into CSV

Subject: Re: [xsl] Convert XML elements with extended attributes into CSV
From: Jeni Tennison <mail@xxxxxxxxxxxxxxxx>
Date: Sat, 26 May 2001 09:31:48 +0100
Hi Xiaocun,

> 1. Is the above solution fesible?

Yes.

> 2. Is there better way to do this?

Well, since you have the RFQExtendAttrDef elements giving you the
extended attribute definitions, you don't have to do a two-pass
solution (which is what you're describing).  Instead, you iterate over
each of the LineItem elements and within that iterate over the
RFQExtendAttrDef elements to get the relevant values out:

<xsl:template match="RFQ">
   <!-- set up $extended-attrs to hold the relevant extended
        attributes -->
   <xsl:variable name="extended-attrs"
                 select="RFQExtendAttrDef[@Domain = 'line_item']" />

   <!-- extended attributes section -->
   <!-- column specification -->
   <xsl:text>Domain,Code,Name&#xA;</xsl:text>
   <!-- content -->
   <!-- iterate over extended attributes for content -->
   <xsl:for-each select="$extended-attrs">
      <xsl:value-of select="concat(@Domain, ',', @Code, ',',
                                   @Name, '&#xA;')" />
   </xsl:for-each>

   <!-- line item section -->
   <!-- column specification -->
   <xsl:text>&#xA;Name,Category,</xsl:text>
   <!-- iterate over extended attributes to get codes (or names?) -->
   <xsl:for-each select="$extended-attrs">
      <xsl:value-of select="@Code" />
      <xsl:if test="position() != last()">,</xsl:if>
   </xsl:for-each>
   <xsl:text>&#xA;</xsl:text>

   <!-- content -->
   <!-- iterate over line items for content -->
   <xsl:for-each select="LineItem">
      <!-- get name and category from attributes -->
      <xsl:value-of select="concat(@Name, ',', @Category, ',')" />
      <!-- set up variable to hold the values of the extended
           attributes on the line item -->
      <xsl:variable name="line-item-attrs" select="ExtendAttr" />
      
      <!-- iterate over the global extended attributes -->
      <xsl:for-each select="$extended-attrs">
         <!-- set up a variable to hold the code -->
         <xsl:variable name="code" select="@Code" />
         <!-- give the value of the line item's extended attribute
              whose Code attribute is that code -->
         <xsl:value-of select="$line-item-attrs[@Code = $code]" />
         <xsl:if test="position() != last()">,</xsl:if>
      </xsl:for-each>
      <xsl:text>&#xA;</xsl:text>
   </xsl:for-each>
</xsl:template>

> 3. If there is no better way to do this, how can the first step,
> i.e. build the header node, be achieved?

You could set up a variable to hold the header node and then turn it
into a node set (rather than an RTF) so that you can use it:

   <xsl:variable name="header-rtf">
      <LineItemHeader>
         <cell column="1">Name</cell>
         <cell column="2">Category</cell>
         <xsl:for-each select="$extended-attrs">
            <cell column="{position() + 2}">
               <xsl:value-of select="@Code" />
            </cell>
         </xsl:for-each>
      </LineItemHeader>
   </xsl:variable>
   <xsl:variable name="header" select="exsl:node-set($header-rtf)" />

(Note: exsl:node-set() is supported in Saxon and 4XSLT - for other
processors you'll have to use processor-specific versions of
node-set().)

> 4. Would this solution be still fesible if the RFQExtendAttrDef
> elements does NOT exist? (this is a possibility in certain cases)
> Building the header node would require scan all LineItem elements
> for unique attributes.

Yes - it just means that you have to get the value for $extended-attrs
in a more complicated way.  The easiest thing to do would be to use a
Muenchian solution.  Set up a key that matches ExtendAttr elements
according to their @Code attribute:

<xsl:key name="extended-attrs" match="ExtendAttr" use="@Code" />

Then you can get the unique values with:

   LineItem/ExtendAttr[count(.|key('extended-attrs', @Code)[1]) = 1]

or

   LineItem/ExtendAttr[generate-id() =
                       generate-id(key('extended-attrs', @Code)[1])]

I hope that helps,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/



 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread