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

Re: Legibility, repetition, nesting

Subject: Re: Legibility, repetition, nesting
From: "Alan Painter alan.painter@xxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Mon, 20 Jul 2020 20:39:25 -0000
Re:  Legibility
Hey David,

I entirely agree with the "how do I make this readable and palatable and
easy to break up and maintain" approach and I think that it's a worthy
cause to uphold.

I'm thinking that this is essentially an established context of "variables"
and also perhaps the current context node upon which an independent
function needs to be called.

I'm thinking of the following objectives

   - have a predicate for determining what "function" to call (and that is
   currently the content and the order of the "when" tests)
   - keep the "predicate" and the "function" paired together within a same
   module, possibly grouped with other function/predicate pairs

The advent of Saxon 10 should allow higher-order functions for doing just
this with the community edition.

I'm thinking of an Array of Maps, each map having a single entry with
structure "map(function(<signature>) as xs:boolean, function(<signature>)
as item()*)".
The signatures for the predicates and functions would probably be identical.
The array signature would be array(map(function(<signature>) as xs:boolean,
function(<signature>) as item()*))
The single-entry maps are kept in an array so that they can be tested
in-order, the same as the "when" elements' predicates are tested in-order.

An iteration could then do the trick, something along the lines of:

<xsl:variable name="predicateFunctionPairArray"
as="array(map(function(<signature>) as xs:boolean, function(<signature>) as
item()*))" >
    <xsl:map-entry key="predicateA" select="functionA" />
    <xsl:map-entry key="predicateB" select="functionB" />
</xsl:variable>

<xsl:iterate select="$predicateFunctionPairArray" >
    <xsl:if test="map:keys(.)(<params according to the signature>)" >
        <xsl:sequence select=".(map:keys(.))(<params according to the
signature>)" />
        <xsl:break/>
    </xsl:if>
</xsl:iterate>

The definitions of the predicates and functions can be in separate modules
which are then included in the module containing the iteration.

The function signatures can be simplified if the variables and context node
in the outer context are grouped into a map or array.

I'm sure that there are some errors in the above but wanted to outline this
suggestion.

best regards

-alan



On Mon, Jul 20, 2020 at 8:23 PM David Birnbaum djbpitt@xxxxxxxxx <
xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote:

> Dear Syd (cc xsl-list),
>
> Thanks for the quick response. As you note, the actual main template does
> a lot of things that are common to all types before it gets to the
> <xsl:choose>, and if I write completely separate templates for each of the
> types, I would need to repeat that shared code verbatim in each of the
> type-specific templates. The variables do have to be inside the templates
> because they are specific to each item. It isn't just variables, there are
> about 30 lines of code common to all items, including variable
> declarations, literal result elements (depending on variables), copies of
> elements and attributes. and a couple of for-each statements, with the
> <xsl:choose> inside the inner for-each.
>
> Best,
>
> David
>
>
>
> On Mon, Jul 20, 2020 at 1:32 PM Bauman, Syd s.bauman@xxxxxxxxxxxxxxxx <
> xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote:
>
>> Hi David!
>>
>> I donbt feel qualified to pontificate on *best* practice, but happy to
>> suggest pros and cons of alternatives. But first, letbs make sure I have
>> this rightbthe current basic structure is roughly as follows:
>>
>>   <xsl:template match="item">
>>     <xsl:variable name="pre-choose-var-1" select="''"/>
>>     <xsl:variable name="pre-choose-var-2" select="''"/>
>>     <xsl:copy>
>>       <xsl:sequence select="common-stuff"/>
>>       <xsl:choose>
>>         <xsl:when test="@type eq '001'"><!-- 001-specific --></xsl:when>
>>         <xsl:when test="@type eq '002'"><!-- 002-specific --></xsl:when>
>>         <!-- ... -->
>>         <xsl:when test="@type eq '133'"><!-- 133-specific --></xsl:when>
>>         <xsl:when test="@type eq '134'"><!-- 134-specific --></xsl:when>
>>       </xsl:choose>
>>     </xsl:copy>
>>   </xsl:template>
>>
>> If so, I wonder if dividing the one huge template up into 134 small ones
>> would be more manageable:
>>
>>   <xsl:template match="item[@type eq '001']">
>>     <xsl:variable name="pre-choose-var-1" select="''"/>
>>     <xsl:variable name="pre-choose-var-2" select="''"/>
>>     <xsl:copy>
>>       <xsl:call-template name="do-common-stuff"/>
>>       <!-- 001-specific -->
>>     </xsl:copy>
>>   </xsl:template>
>>
>> No bmainb template at all. If the pre-choose variables do not depend
on
>> @type, a lot of repetition, though. (I am presuming the variables need to
>> be inside the template, which you implied, but did not state, if I read
>> right.)
>>
>> Just a thought. Stay safe, keep coding.
>>
>> ------------------------------
>>
>> I write here for advice about Best Practice. The question is at the end;
>> because I am constitutionally unable to be concise, the long narrative
>> before it is context.
>>
>> I'm developing an XSLT stylesheet that processes 134 different types of
>> items (same generic identifier, distinguished by an attribute value). For
>> each item, regardless of type, I create several variables, do an
>> <xsl:copy>, and inside that first create some other content that is common
>> to all items, regardless of type, and then use <xsl:choose> to handle the
>> types differently, according to their idiosyncrasies. I began by
>> implementing this as a single template with a long <xsl:choose> deeply
>> nested inside it, which has the advantage of avoiding unnecessary
>> repetition, since the shared operations are outside the <xsl:choose>. It
>> works, but perfectionism is a terrible curse ...
>>
>> Perhaps I'm being arbitrarily fastidious, but the <xsl:choose> inside the
>> deep nesting feels awkward; I wind up with one template that runs to more
>> than a thousand lines, where the <xsl:choose> is seven levels deep. This
>> made me wonder whether off-loading the type-specific tasks to separate
>> templates or functions, which could be called from the appropriate place,
>> would keep the main template down to a more manageable size. Specifically,
>> I'd like to be able to put the code blocks currently inside of the
>> <xsl:when> statements somewhere other than deep inside a single main
>> template.
>>
>> One implementation of this approach that works, but comes with its own
>> issues, is using an <xsl:next-match> with auxiliary lower-priority
>> templates that match item[@type eq 'x']. This lets me break out the
>> type-specific code into separate templates. The reason this is not wholly
>> satisfactory is that I have to pass all of the variables into these
>> separate templates as parameters, so I wind up repeating the same
>> <xsl:param> statements inside each of the secondary templates. That much
>> repetition feels suboptimal.
>>
>> The only approach that occurs to me that might simultaneously eliminate
>> repetition and avoid putting all of the processing inside a single
>> thousand-line template, most of which is the <xsl:choose> with all of the
>> type-specific handling inside <xsl:when> children, is to put the
>> type-specific processing into separate files, with an <xsl:when> root, and
>> then <xsl:include> them inside the <xsl:choose>. One downside seems to be
>> that they will not be valid XSLT (they wonbt have the necessary wrapper
>> boilerplate and the variables they use wonbt be defined inside them),
which
>> I think I could overcome by using an <oXygen/> "master document", which
>> would cause them to be validated in context. That isn't ideal, since it's
>> tied to a specific development environment, but since that happens to be
my
>> usual development environment, the objection is philosophical (= can be
>> ignored in the interest of Getting The Job Done), rather than practical.
>>
>> So: Is there a Best Practice approach to breaking out the type-specific
>> treatment of the different types of items that avoids both 1) unnecessary
>> repetition and 2) embedding a single thousand-line <xsl:choose>, which
>> contains all of the type-specific operations, seven levels deep inside a
>> template?
>>
>>
>> XSL-List info and archive <http://www.mulberrytech.com/xsl/xsl-list>
>> EasyUnsubscribe <http://lists.mulberrytech.com/unsub/xsl-list/3318727> (by
>> email)
>>
> XSL-List info and archive <http://www.mulberrytech.com/xsl/xsl-list>
> EasyUnsubscribe <http://lists.mulberrytech.com/unsub/xsl-list/552232> (by
> email <>)

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.