xsl-list
[Top] [All Lists]

Re: [xsl] XSL | index-of()

2019-09-27 10:50:30
Your style sheet uses for-each to do the processing and in the context of this 
very small example that seems OK but probably worth mentioning that in a larger 
transform that's doing more than just generating the narrow result here you 
would normally prefer an apply-templates solution, i.e., something like:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
  xmlns:xs="http://www.w3.org/2001/XMLSchema"; exclude-result-prefixes="xs" 
version="2.0">

  <xsl:output method="xml" encoding="UTF-8" indent="yes"/>

  <xsl:template match="/">
    <xsl:apply-templates/>
  </xsl:template>

  <xsl:template match="all">
    <xsl:variable name="abbr" select="abbreviations/abbr"/>
    <all>
      <xsl:apply-templates>
        <xsl:with-param name="abbr" as="element()*" tunnel="yes" 
select="$abbr"/>
      </xsl:apply-templates>
    </all>
  </xsl:template>
  
  <xsl:template match="abbreviations">
    <!-- Don't do anything with these for now, maybe later -->
  </xsl:template>
  
  <xsl:template match="documents">
    <xsl:apply-templates/>
  </xsl:template>

  <xsl:template match="doc">
    <xsl:param name="abbr" as="element()*" tunnel="yes" select="()"/>

    <xsl:variable name="actdoc" select="."/>
    <xsl:if
      test="
        some $a in $abbr
          satisfies contains($actdoc, concat('(', $a, ')'))">
      <doc no="{@no}">
        <xsl:value-of select="."/>
      </doc>
    </xsl:if>

  </xsl:template>
  
  <xsl:template match="*">
    <xsl:message>+ [WARN] Unhandled element <xsl:value-of 
select="concat(name(..), '/', name(.))"/></xsl:message>
  </xsl:template>
  
  <xsl:template match="text()">
    <!-- Suppress text by default -->
  </xsl:template>

</xsl:stylesheet>

(This is an XSLT 2 transform--there are ways to make it more compact with XSLT 
3.)

The latest template that suppresss text() nodes is there because in this 
example you are not doing the usual default copying of text to output so I 
added that template. In a more typical document processing transform you would 
not suppress text() nodes by default. Because the default behavior of XSLT is 
to copy text nodes to the output you need to explicitly suppress them in this 
case.

It may seem a little more verbose but it is much more flexible and establishes 
the pattern for adding additional functionality. It also makes it easy to find 
the processing associated with a specific element if each major element has a 
corresponding template, as opposed to having to look inside more complex 
templates to see if any for-each happens to operate on some element. As your 
transforms become larger this becomes much more important. 

If you are moving to XSLT from more traditional procedural languages it is 
natural to use for-each but you should try to move to using apply-templates as 
much as possible.

Cheers,

Eliot

--
Eliot Kimber
http://contrext.com
 

On 9/27/19, 7:05 AM, "Janine S. loderndesfeuer(_at_)gmx(_dot_)de" 
<xsl-list-service(_at_)lists(_dot_)mulberrytech(_dot_)com> wrote:

    Hello everybody and thank you very much for your good answers. They help me 
to better understand XSL. I was also able to help myself with two for-each 
loops:
     
    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
      xmlns:fn="http://www.w3.org/2005/xpath-functions"; version="2.0"
      exclude-result-prefixes="#all">
      <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
      <xsl:template match="all">
        <xsl:variable name="abbr" select="abbreviations/abbr"/>
        <all>
          <xsl:for-each select="//doc">
            <xsl:variable name="actdoc" select="."/>
            <xsl:variable name="no" select="@no"/>
            <xsl:for-each select="$abbr">
              <xsl:if test="fn:contains($actdoc, .)">
                <doc no="{$no}">
                  <xsl:value-of select="."/>
                </doc>
              </xsl:if>
            </xsl:for-each>
          </xsl:for-each>
        </all>
      </xsl:template>
    </xsl:stylesheet>
    
     
    Many greetings
    Janine
     
    Gesendet: Freitag, 27. September 2019 um 12:46 Uhr
    Von: "Mukul Gandhi gandhi(_dot_)mukul(_at_)gmail(_dot_)com" 
<xsl-list-service(_at_)lists(_dot_)mulberrytech(_dot_)com>
    An: xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
    Betreff: Re: [xsl] XSL | index-of()
    Hi Janine,
        Here's the stylesheet that works,
    
     
    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
                             xmlns:xs="http://www.w3.org/2001/XMLSchema";
                             xmlns:fn="http://stylesheet_fns";
                             exclude-result-prefixes="xs fn"
                             version="2.0">
                   
        <xsl:output method="xml" indent="yes"/>                
    
        <xsl:template match="all">
           <all>
              <xsl:for-each select="documents/doc[fn:isIncludeDoc(.)]">
                 <doc no="{@no}"><xsl:value-of 
select="substring-before(substring-after(., '('), ')')"/></doc>
              </xsl:for-each>
           </all>
        </xsl:template>
       
        <xsl:function name="fn:isIncludeDoc" as="xs:boolean">
           <xsl:param name="doc" as="element(doc)"/>
                 
           <xsl:sequence select="some $abbr in $doc/../../abbreviations/abbr 
satisfies contains($doc, concat('(', $abbr, ')'))"/>
        </xsl:function>
    
    </xsl:stylesheet>
     
    On Fri, Sep 27, 2019 at 2:37 PM Janine Lantzsch 
loderndesfeuer(_at_)gmx(_dot_)de 
<xsl-list-service(_at_)lists(_dot_)mulberrytech(_dot_)com> wrote:
    
    Hello community,
     
    I am new in this list and hope very much that someone can help me or give 
me an input with which I can continue to work.
    
    I would like to use XSL to check whether a abbreviation from a list appears 
in a certain string of recurring elements. The abbreviation is always written 
in brackets. The source file looks like this (very simplified):
     
    <?xml version="1.0" encoding="UTF-8"?>
    <all>
        <abbreviations>
                <abbr>ABG</abbr>
                <abbr>AGI</abbr>
                <abbr>BBL</abbr>
                <abbr>ECK</abbr>
        </abbreviations>
        <documents>
            <doc no="1">The abbreviation (ABG) appears in this doc.</doc>
            <doc no="2">This doc has no shortcut.</doc>
            <doc no="3">An abbreviation (BBL).</doc>
            <doc no="4">And here (ECK).</doc>
            <doc no="5">And here again (ECK).</doc>
        </documents>
    </all>
    
    Only unfortunately I still have a bug somewhere with the index-of. Maybe 
the more experienced of you will see right away what's wrong with my code. I've 
been brooding since last night and can't find a solution :(
     
    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; 
xmlns:fn="http://www.w3.org/2005/xpath-functions"; version="2.0">
        <xsl:output method="xml" encoding="UTF-8"/>
        <xsl:template match="all">
            <xsl:variable name="abbr" select="abbreviations/abbr"/>
            <all>
                <xsl:for-each select="//doc">
                    <xsl:variable name="actdoc" select="."/>
                    <xsl:if test="fn:contains($actdoc, fn:index-of($abbr, 
$actdoc))">
                        <doc>
                            <xsl:attribute name="no"><xsl:value-of 
select="@no"/></xsl:attribute>
                            <xsl:value-of select="$actdoc"/>
                        </doc>
                    </xsl:if>
                </xsl:for-each>
            </all>
        </xsl:template>
    </xsl:stylesheet>
    
    The output should look something like this:
     
    <all>
        <doc no="1">ABG</doc>
        <doc no="3">BBL</doc>
        <doc no="4">ECK</doc>
        <doc no="5">ECK</doc>
    </all>
    
    Thank you so much for your help!
     
    Many greetings
    Janine S.
    
    
    
    
    
     
     
    
     
    --
    
    Regards,
    Mukul Gandhi
    
    
    
    
    XSL-List info and archive 
<http://www.mulberrytech.com/xsl/xsl-list>EasyUnsubscribe 
<http://lists.mulberrytech.com/unsub/xsl-list/3305161> (by email <>)
    
    
    
    
    
    
    
    XSL-List info and archive 
<http://www.mulberrytech.com/xsl/xsl-list>EasyUnsubscribe 
<http://lists.mulberrytech.com/unsub/xsl-list/1278982>
    (by email <>)
    
    
    
    
--~----------------------------------------------------------------
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
EasyUnsubscribe: http://lists.mulberrytech.com/unsub/xsl-list/1167547
or by email: xsl-list-unsub(_at_)lists(_dot_)mulberrytech(_dot_)com
--~--

<Prev in Thread] Current Thread [Next in Thread>