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

Subject: Re: [xsl] XSL | index-of()
From: "Eliot Kimber ekimber@xxxxxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Fri, 27 Sep 2019 15:50:23 -0000
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


o;?On 9/27/19, 7:05 AM, "Janine S. loderndesfeuer@xxxxxx"
<xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> 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.mukul@xxxxxxxxx"
<xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
    An: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
    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@xxxxxx
<xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> 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 <>)

Current Thread