xsl-list
[Top] [All Lists]

Re: [xsl] constructing an element with an element's content based on the content of sibling element

2012-06-11 02:06:06
You're welcome. 

I'm beginning to suspect that, like many folks who come to XSLT from
procedural languages like Perl or C, you are using mostly "pull"
processing (get X, put it here; get Y, put it next ...) rather than
mostly "push" processing (whenever you hit an X, do this; whenever
you hit a Y, do that).

The code I sent presumed that your XSLT was busy processing the
*parent* of the <productidentifier> element (e.g. a <containeditem>,
<notforsale>, <product>, <relatedproduct>, or <set>) when you wanted
the ISBN spit out as a <controlfield>. If you're going to use 
      <xsl:for-each select="productidentifier">
        <xsl:call-template name="isbn"/>
      </xsl:for-each>
then in the "isbn" template you're calling, the context node will be
the <productidentifier>. Thus to test for the existence of a <b221>
child element with the value '15', you test any one of the following,
which are equivalent
   self::productidentifier/child::b221 = '15'
   self::productidentifier/b221 = '15'
   ./child::b221 = '15'
   ./b221 = '15'
   b221 = '15'

So in the code you just posted, 
<xsl:template name="isbn" match="productidentifier">
  <xsl:choose>
   <xsl:when test="productidentifier/b221 = '15'">
     <xsl:apply-templates select="productidentifier[b221='15']"/>

The template is being fired with a <productidentifier> as the current
node. So the test "productidentifier/b221" is asking to look at each
<b221> child of the <productidentifier> child of the currently being
processed <productidentifier>. Since there are no <productidentifier>
elements as children of the current <productidentifier>, the test can
never be true.

So you might try something like

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
  xmlns:marc="http://www.loc.gov/MARC21/slim"; version="2.0">

  <xsl:template match="/">
    <marc:pretend-wrapper-to-hold-multiple-records>
      <xsl:apply-templates select="wrapper/product"/>
    </marc:pretend-wrapper-to-hold-multiple-records>
  </xsl:template>

  <xsl:template match="product">
    <marc:record>
      <xsl:for-each select="productidentifier">
        <xsl:call-template name="isbn"/>
      </xsl:for-each>
    </marc:record>
  </xsl:template>

  <xsl:template name="isbn" match="productidentifier">
    <xsl:choose>
      <!-- first take care of "I am ISBN 13" case -->
      <xsl:when test="child::b221 = '15'">
        <controlfield tag="001">
          <xsl:text>ISBN13 = </xsl:text>
          <xsl:value-of select="b244"/>
        </controlfield>
      </xsl:when>
      <!-- then ignore case where I have a sibling that is ISBN 13 -->
      <xsl:when test="parent::*/child::productidentifier/child::b221 = '15'"/>
      <!-- no sibling ISBN 13, so use ISBN 10, if that's what I am -->
      <xsl:when test="child::b221 = '02'">
        <controlfield tag="001">
          <xsl:text>ISBN10 = </xsl:text>
          <xsl:value-of select="b244"/>
        </controlfield>
      </xsl:when>
      <xsl:otherwise>
        <xsl:message>Danger, Will Robinson! a 'productidentifier' that is 
confusing</xsl:message>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

Although I personally prefer the previous version.


Thanks very much for your reply, Syd.

My apologies, I didn't search the XSL archive specifically, many of
the results from my google search queries included the archive. I
also poured over Kay's tomb for the functions not(), exists(),
empty() (got really excited for a moment with element
-available()).

My stylesheet has nearly 1300 lines of code transforming ONIX for
Books 2.1 into MARCXML. I'm using XSLT 2.0 (use tokenize() not
available in 1.0); Stylus Studio Enterprise edition 2010.

In fact, the scenario for the need of an alternate ISBN is small
but the variability of publisher encoding warrants this test I
think.

In place of the stylesheet segment in my OP, I substituted a
call-template based on your reply. The main template of my
stylesheet matches the product element with ONIXMessage as the
context and I use call-template for the construction of 1XX, 7XX
and 245 MARC fields given the complexity of those fields with
respect to name and title elements in ONIX as well as punctuation
in the MARCXML fields.

Hadn't thought to use call-template here but also hadn't considered
the predicates you offered, so I tried this based on your
suggestion but get no controlfields at all. Wan't sure about the
context of the value-of select paths, so tried value-of
select="following-sibling::b244", too.

<marc:record>
.
.
<xsl:for-each select="productidentifier">
  <xsl:call-template name="isbn"/>
</xsl:for-each>
.
.
</marc:record

<xsl:template name="isbn" match="productidentifier">
  <xsl:choose>
   <xsl:when test="productidentifier/b221 = '15'">
     <xsl:apply-templates select="productidentifier[b221='15']"/>
    </xsl:when>
    <xsl:otherwise>
    <xsl:apply-templates select="productidentifier[b221='02']"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

<xsl:template match="productidentifier[b221 eq '02']">
  <controlfield tag="001">
    <xsl:text>xyz</xsl:text>
    <xsl:value-of select="b244"/>
  </controlfield>
</xsl:template>

<xsl:template match="productidentifier[b221 eq '15']">
  <controlfield tag="001">
   <xsl:text>xyz</xsl:text>
   <xsl:value-of select="b244"/>
  </controlfield>
</xsl:template>

Most of my earlier efforts centered on the use of
xsl:choose and xsl:otherwise.  All failed so think I'm
lacking a basic understanding of an important XSLT
concept.

Tried attaching a file with 3 records with the variation of presence
of different product identifiers but my message was rejected even
though in a text file.

--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--