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 |
---|
|
<- Previous | Index | Next -> |
---|---|---|
Aw: Re: [xsl] XSL | index-of(), Janine S. loderndesf | Thread | [xsl] [ANN] XML, Schematron, XSLT c, B Tommie Usdin btusd |
Aw: Re: [xsl] XSL | index-of(), Janine S. loderndesf | Date | [xsl] [ANN] XML, Schematron, XSLT c, B Tommie Usdin btusd |
Month |