[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

XML-to-XML recursive template handling

Subject: XML-to-XML recursive template handling
From: Lynn Murdock <lmurdock@xxxxxxxx>
Date: Sun, 11 Dec 2011 15:42:59 -0800
 XML-to-XML recursive template handling
Hi Wendell-

Yes, your solution worked, and that is what I was moving toward; I just didn't
quite know how to get there, and thought I needed to pass a parameter into a
called template to accomplish it. Thank you!

I do have access to an XSLT 2.0 processor, and can probably modify these
stylesheets to use XSLT 2.0... For future reference, would you mind explaining
what the more graceful XSLT 2.0 solution would be?


Thanks again-

Lynn


Lynn Murdock, MLIS
Web Producer
Public Library of Science (PLoS)
http://www.plos.org<http://www.plos.org/>


On Dec 9, 2011, at 10:10 PM,
<xsl-list-digest-help@xxxxxxxxxxxxxxxxxxxxxx<mailto:xsl-list-digest-help@list
s.mulberrytech.com>>
<xsl-list-digest-help@xxxxxxxxxxxxxxxxxxxxxx<mailto:xsl-list-digest-help@list
s.mulberrytech.com>> wrote:

Date: Fri, 09 Dec 2011 11:33:57 -0500
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx<mailto:xsl-list@xxxxxxxxxxxxxxxxxxxxxx>
From: Wendell Piez <wapiez@xxxxxxxxxxxxxxxx<mailto:wapiez@xxxxxxxxxxxxxxxx>>
Subject: Re:  XML-to-XML recursive template handling
Message-ID:
<4EE23875.8060200@xxxxxxxxxxxxxxxx<mailto:4EE23875.8060200@xxxxxxxxxxxxxxxx>>

Dear Lynne,

I don't know the NLM tool, so I'm guessing a bit.

In general, however, with this sort of problem you have two choices:

1. Pipeline. Move the elements out of the fn-group (and perform other
modifications) and then clean up (for example, removing an empty
fn-group) in a separate process. This can be done either at the "macro"
level (the entire document) or (in XSLT 2.0) the "micro" level (just the
fn-group).

Or 2. Write your code to recognize an fn-group from which all fn
elements will be moved, and not process it.

Your code shows signs that you are trying to achieve something like a
micropipeline in XSLT 1.0. In simply cases (such as yours) this is not
impossible, although it entails the XSLT 1.0 version of (as it were)
standing on your hands.

So one thing to consider is whether you can't modify your general
approach; either use XSLT 2.0, or use a pipeline processor (such as
XProc) or pipeline the old-fashioned way (pipeline the entire document
not just the fn-group element). Having mastered these methods, this kind
of problem will be much easier going forward.

Assuming you don't have the means or resources to do that, looking at
your code, there are a couple of odd things:

<xsl:template match="fn-group">
  <xsl:param name="node"><xsl:apply-templates/></xsl:param>
  <!-- A parameter is declared and the results of applying templates
       to the children of the fn-group are bound to it.
       (Why a parameter? is this ever overridden from elsewhere?) -->

  <!-- Next, we copy the fn-group if it has fn children, and inside, we
       process the fn children -->
  <xsl:if test="fn">
    <fn-group>
      <xsl:for-each select="fn">
        <!-- code elided here. Each fn is either copied, or it isn't -->
      </xsl:for-each>
    </fn-group>

    <!-- next we call the emptyfn template, passing $node in -->
    <xsl:call-template name="emptyfn">
      <xsl:with-param name="node" select="$node"/>
    </xsl:call-template>
  </xsl:if>
</xsl:template>

<xsl:template name="emptyfn">
  <!-- but 'emptyfn' is a no-op. If $node tests true, it ...
       does nothing -->
  <xsl:param name="node"/>
  <xsl:if test="not($node)"/>
</xsl:template>

Remember I'm guessing a little, but what I think you want is something
more like this:

<xsl:template match="fn-group">
  <xsl:variable name="fn-results">
    ... for-each logic goes here ... or do the same thing, more
    gracefully, with templates ...
  </xsl:variable>
  <xsl:if test="normalize-space($fn-results">
    <fn-group>
      <xsl:copy-of select="fn-results"/>
    </fn-group>
  </xsl:if>
</xsl:template>

This is effectively an XSLT 1.0 "poor man's" version of a proper
micropipeline such as we could do in XSLT 2.0. Basically it processes
the fn children of the fn-group and binds the results to a variable. The
results are an XSLT 1.0 temporary tree: it either contains copies of the
fn elements, or it doesn't (if there were none we wanted to copy).

If the latter, the temporary tree will be cast to an empty string by the
normalize-space() test in the subsequent xsl:if, and no fn-group will be
created. If the set of fn elements resulted in non-whitespace content,
however, this tests true, and they are copied in, inside an fn-group.

This might be all there is to it ... or maybe not, if there are details
we have missed.

In XSLT 2.0 you could do the same thing, only more properly and more
robustly. In particular, here the XSLT 1.0 has to make assumptions such
as that the fn elements are going to have string values.

I hope this helps. Let us know.

Cheers,
Wendell

--
======================================================================
Wendell Piez                            mailto:wapiez@xxxxxxxxxxxxxxxx
Mulberry Technologies, Inc.
http://www.mulberrytech.com<http://www.mulberrytech.com/>
17 West Jefferson Street                    Direct Phone: 301/315-9635
Suite 207                                          Phone: 301/315-9631
Rockville, MD  20850                                 Fax: 301/315-8285
----------------------------------------------------------------------
  Mulberry Technologies: A Consultancy Specializing in SGML and XML
======================================================================

------------------------------

Date: Thu, 8 Dec 2011 21:50:11 -0800
To: "xsl-list@xxxxxxxxxxxxxxxxxxxxxx<mailto:xsl-list@xxxxxxxxxxxxxxxxxxxxxx>"
<xsl-list@xxxxxxxxxxxxxxxxxxxxxx<mailto:xsl-list@xxxxxxxxxxxxxxxxxxxxxx>>
From: Lynn Murdock <lmurdock@xxxxxxxx<mailto:lmurdock@xxxxxxxx>>
Subject: XML-to-XML recursive template handling
Message-ID:
<91FE79B4-51AE-4F49-8C5A-055CE08F6614@xxxxxxxx<mailto:91FE79B4-51AE-4F49-8C5A
-055CE08F6614@xxxxxxxx>>

Hi-

I am doing an XML-to-XML transform in which I need to rearrange elements in=
such a way that sometimes the context element is left empty when I am fini=
shed rearranging (but not always). As a second step, I want to strip these =
newly empty elements from the final output, and I am having trouble doing s=
o.

For those of you who are familiar with the NLM's tool to convert older DTDs=
to the 3.0 DTD, I am modifying the base.xsl component of the 2publishing3 =
conversion. Essentially, everything is copied through except elements that =
need to be modified in one way or another. Specifically, I am moving certai=
n footnotes out of <fn-group> and into other locations in the document. If =
the only footnotes in the original <fn-group> are those that I move, then a=
fter this action, the result is <fn-group/>, which I want to remove from th=
e final output.

I've tried several methods, and nothing I've tried is working. Any pointers=
would be very much appreciated. I think that the issue is that I'm not ful=
ly understanding how the recursion works here to re-process a node that I'v=
e already processed once (or maybe it has to do with the default copy metho=
d for the stylesheet?)...

(Default copy:
<xsl:template match=3D"* | @* | text()" priority=3D"-1">
<xsl:copy>
<xsl:apply-templates select=3D"@*|*|text()"/>
</xsl:copy>
</xsl:template>)

XSL version=3D1.0
Processor=3DOxygen's built-in saxon (Oxygen version 11.2 for Linux)

Here's the relevant section of the stylesheet:

<xsl:template match=3D"fn-group">
 <xsl:param name=3D"node"><xsl:apply-templates/></xsl:param>
 <xsl:if test=3D"fn">
<fn-group>
   <xsl:for-each select=3D"fn">
<xsl:choose>
                      <!-- retag no fn-type to fn-type=3D"other" -->
<xsl:when test=3D"not(@fn-type)">
<fn fn-type=3D"other">
<xsl:apply-templates/>
</fn>
</xsl:when>
<xsl:when test=3D"@fn-type=3D'other'">
<fn fn-type=3D"other">
<xsl:apply-templates/>
</fn>
</xsl:when>
<!-- suppress here, moved to author-notes -->
<xsl:when test=3D"fn-type=3D'conflict'"/>
<!-- suppress here, retagged into funding-statement -->
<xsl:when test=3D"fn-type=3D'financial-disclosure'"/>
</xsl:choose>
   </xsl:for-each>
</fn-group>
<xsl:call-template name=3D"emptyfn">
<xsl:with-param name=3D"node" select=3D"$node"/>
</xsl:call-template>
    </xsl:if>
</xsl:template>

<xsl:template name=3D"emptyfn">
<xsl:param name=3D"node"/>
<xsl:if test=3D"not($node)"/>
</xsl:template>

Thanks much-

Lynn

Lynn Murdock, MLIS
Web Producer
Public Library of Science (PLoS)
http://www.plos.org<http://www.plos.org/>

Lynn Murdock, MLIS
Web Producer
Public Library of Science (PLoS)
http://www.plos.org



Lynn Murdock, MLIS
Web Producer
Public Library of Science (PLoS)
http://www.plos.org

Current Thread

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2013 All Rights Reserved.