xsl-list
[Top] [All Lists]

[xsl] Re: [XSL-List: The Open Forum on XSL] Digest for 2017-08-30

2017-08-31 07:31:33
Hi Rahul,

I might have an idea what you are trying to achieve, but I still don’t know exactly because something is still missing (see below).

When you write

<xsl:when test="exists($XMLMerge2/ClientInfo/clientdata[name = $Email_from_merge1])">
  <xsl:copy>
    <xsl:copy-of select="node() | @*"/>
  </xsl:copy>
</xsl:when>

you might want to include additional info from $XMLMerge2, such as the Name element that appears in the expected result. You don’t include it though. You will notice that in both xsl:when branches, you use exactly the same instructions. Since the context is the same for both, you will get the same output, which is a verbatim copy of Input1.xml’s clientname elements.

Before the xsl:choose, you might want to define another variable for conciseness:

<xsl:variable name="clientdata" select="$XMLMerge2/ClientInfo/clientdata[name = $Email_from_merge1]" as="element(clientdata)?"/>

Then move the second xsl:when (the one I quoted above) first, and modify it like this:

<xsl:when test="exists($clientdata)">
  <xsl:copy>
<xsl:apply-templates select="@* | node(), $clientdata/clientnameReference/node()"/>
  </xsl:copy>
</xsl:when>

The formerly first, now second, xsl:when might then become an xsl:otherwise.

You didn’t update the sample for input2.xml (or Input2.xml, as you used to call it in the previous message). Therefore we still don’t know where the additional fields like <Name>Bob Robben</Name> in the output should be taken from. I just presume they are below $clientdata/clientnameReference. In order to avoid including $clientdata/clientnameReference/Email again, you might write a template rule that suppresses Email in the output, or you exclude it in the select: $clientdata/clientnameReference/(node() except Email), for example.

Please note that in your sample stylesheet, there again was a tag mismatch. Please do pay more attention when posting questions. The list members tend to be supportive, but they need accurate information and they need to see what your hitherto best effort was. If you post code or input that cannot work, some goodwill is needed on the list members’ part to “auto-correct” your input and expected output, and sometimes this guesswork goes off in the wrong direction.

In addition, please don’t hijack unrelated postings (like the one quoted below) in order to send a reply. If you did only subscribe to the list digest, consider switching to receiving every message before you post a question so that you can answer directly, thereby allowing a nicely ordered thread in the archive: http://www.biglist.com/lists/lists.mulberrytech.com/xsl-list/archives/201708/threads.html

Once we sorted out the basic functionality (and also have seen the complete, accurate input2.xml so that we know where things like <Name>Bob Robben</Name> originate from), we can look into performance or elegance tweaks like replacing xsl:for-each with xsl:for-each-group.

Thanks,

Gerrit


On 31.08.2017 11:31, Rahul Singh wrote:
below code i have modified but not working:

|<xsl:stylesheetversion="2.0"xmlns:xsl="http://www.w3.org/1999/XSL/Transform";><xsl:outputomit-xml-declaration="yes"indent="yes"/><xsl:strip-spaceelements="*"/><xsl:paramname="XMLMerge2"select="document('input2.xml')"/><xsl:keyname="kBymail"match="clientname"use="Email"/><xsl:templatematch="ClientInfo"><ClientInfo><xsl:for-eachselect="clientname"><xsl:variablename="Email_from_merge1"select="Id"/><xsl:choose><xsl:whentest="$XMLMerge2 = ''"><xsl:copy><xsl:copy-ofselect="node() | @*"/></xsl:copy></xsl:when><xsl:whentest="exists($XMLMerge2/ClientInfo/clientdata[name = $Email_from_merge1])"><xsl:copy><xsl:copy-ofselect="node() | @*"/></xsl:copy></xsl:when></xsl:choose></xsl:for-each></objects></xsl:template><xsl:templatematch="Contact[Email = following-sibling::Contact/Email]"/>|


On Thu, Aug 31, 2017 at 2:52 PM, XSL-List: The Open Forum on XSL <xsl-list-service(_at_)lists(_dot_)mulberrytech(_dot_)com <mailto:xsl-list-service(_at_)lists(_dot_)mulberrytech(_dot_)com>> wrote:

    This message contains the recent posts to the XSL-List: The Open
    Forum on XSL
    mailing list managed by Mulberry Technologies, Inc.
    (http://lists.mulberrytech.com).

    ---------- Forwarded message ----------
    From: "Michael Müller-Hillebrand" <mmh(_at_)docufy(_dot_)de 
<mailto:mmh(_at_)docufy(_dot_)de>>
    To: "xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
    <mailto:xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com>"
    <XSL-List(_at_)lists(_dot_)mulberrytech(_dot_)com
    <mailto:XSL-List(_at_)lists(_dot_)mulberrytech(_dot_)com>>
    Cc:
    Bcc:
    Date: Wed, 30 Aug 2017 20:48:55 +0200
    Subject: Can I use xsl:key to select elements up to certain ancestor
    Hi all,

    I had an embarrassing moment today, when I found that the source of
    a severe performance problem was sitting in front of the screen.

    Using XSLT 2.0 I am transforming elements and at many points I have
    to look up the ancestor axis, but only up to an element with an
    attribute "id". Basically I have a deeply nested structure of topics
    and I want to analyze ancestors inside the current topic.

    The nearest topic is easy to find:

    <xsl:variable name="topic" select="ancestor-or-self::*[@id][1]"
    as="element()"/>

    And then I was doing the following to find all ancestors that share
    the same "topic ancestor":

    <xsl:variable name="ancestors-in-topic"
       select="ancestor-or-self::*[ancestor-or-self::* = $topic]"
    as="element()*"/>

    This did not what I expected and also wasted a lot of resources
    because the predicate was true for all or most elements. After some
    testing I went with this:

    <xsl:variable name="ancestors-in-topic"
       select="ancestor-or-self::*[ancestor-or-self::*/generate-id() =
    generate-id($topic)]" as="element()*"/>

    Since that calculation is done very often I am wondering if xsl:key
    could be used to speed things up?

    Any pointers are very welcome, as always, thanks,

    - Michael

    PS: My sample XML and XSLT below.

    <?xml version="1.0" encoding="UTF-8"?>
    <bars id="x0">
       <bar id="x1">
         <bar id="x11">
           <bar id="x12">
             <div>
               <bar id="x13">
                 <div>
                   <p/>
                 </div>
               </bar>
             </div>
           </bar>
         </bar>
       </bar>
    </bars>


    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform
    <http://www.w3.org/1999/XSL/Transform>"
    xmlns:xs="http://www.w3.org/2001/XMLSchema
    <http://www.w3.org/2001/XMLSchema>" version="2.0">
       <xsl:output method="xml" indent="yes" omit-xml-declaration="no"/>
       <xsl:strip-space elements="*"/>

       <xsl:template match="p">
         <xsl:variable name="topic" select="ancestor-or-self::*[@id][1]"
    as="element()"/>
         <xsl:variable name="ancestors-in-topic"
    select="ancestor-or-self::*[ancestor-or-self::*/generate-id() =
    generate-id($topic)]" as="element()*"/>
         <xsl:copy>
           <xsl:attribute name="topic" select="$topic/@id"/>
           <xsl:text>Ancestors: </xsl:text>
            <xsl:sequence select="$ancestors-in-topic/name()"/>
         </xsl:copy>
       </xsl:template>

       <xsl:template match="* | @*">
         <xsl:copy>
           <xsl:apply-templates select="@*, node()"/>
         </xsl:copy>
       </xsl:template>
    </xsl:stylesheet>


    Expected output for <p>: <p topic="x13">Ancestors: bar div p</p>

    ---------- Forwarded message ----------
    From: David Carlisle <d(_dot_)p(_dot_)carlisle(_at_)gmail(_dot_)com
    <mailto:d(_dot_)p(_dot_)carlisle(_at_)gmail(_dot_)com>>
    To: xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
    <mailto:xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com>
    Cc:
    Bcc:
    Date: Wed, 30 Aug 2017 20:08:05 +0100
    Subject: Re: [xsl] Can I use xsl:key to select elements up to
    certain ancestor
    You seem to be listing ancestor-or-self rather than ancestor, I think
    you only need to go up the ancestor axis once in each case, something
    like

    <xsl:stylesheet version="2.0"
             xmlns:xsl="http://www.w3.org/1999/XSL/Transform
    <http://www.w3.org/1999/XSL/Transform>">


      <xsl:template match="/">
       <xsl:apply-templates select="//p"/><!-- just for testing-->
      </xsl:template>


      <xsl:template match="*">
       <xsl:copy>
        <xsl:apply-templates select="." mode="a"/>
       </xsl:copy>
      </xsl:template>

      <xsl:template match="*" mode="a">
       <xsl:param name="trail" select="()"/>
       <xsl:apply-templates select="parent::*" mode="a">
        <xsl:with-param name="trail" select="name(),$trail"/>
       </xsl:apply-templates>
      </xsl:template>

      <xsl:template match="*[@id]" mode="a">
       <xsl:param name="trail" select="()"/>
        <xsl:copy-of select="@id,'Ancestors:', name(), $trail"/>
      </xsl:template>

    </xsl:stylesheet>


    which makes


    <p id="x13">Ancestors: bar div p</p>

    On 30 August 2017 at 19:49, Michael Müller-Hillebrand 
mmh(_at_)docufy(_dot_)de
    <mailto:mmh(_at_)docufy(_dot_)de>
    <xsl-list-service(_at_)lists(_dot_)mulberrytech(_dot_)com
    <mailto:xsl-list-service(_at_)lists(_dot_)mulberrytech(_dot_)com>> wrote:
     > Hi all,
     >
     > I had an embarrassing moment today, when I found that the source
    of a severe performance problem was sitting in front of the screen.
     >
     > Using XSLT 2.0 I am transforming elements and at many points I
    have to look up the ancestor axis, but only up to an element with an
    attribute "id". Basically I have a deeply nested structure of topics
    and I want to analyze ancestors inside the current topic.
     >
     > The nearest topic is easy to find:
     >
     > <xsl:variable name="topic" select="ancestor-or-self::*[@id][1]"
    as="element()"/>
     >
     > And then I was doing the following to find all ancestors that
    share the same "topic ancestor":
     >
     > <xsl:variable name="ancestors-in-topic"
     >   select="ancestor-or-self::*[ancestor-or-self::* = $topic]"
    as="element()*"/>
     >
     > This did not what I expected and also wasted a lot of resources
    because the predicate was true for all or most elements. After some
    testing I went with this:
     >
     > <xsl:variable name="ancestors-in-topic"
     >   select="ancestor-or-self::*[ancestor-or-self::*/generate-id() =
    generate-id($topic)]" as="element()*"/>
     >
     > Since that calculation is done very often I am wondering if
    xsl:key could be used to speed things up?
     >
     > Any pointers are very welcome, as always, thanks,
     >
     > - Michael
     >
     > PS: My sample XML and XSLT below.
     >
     > <?xml version="1.0" encoding="UTF-8"?>
     > <bars id="x0">
     >   <bar id="x1">
     >     <bar id="x11">
     >       <bar id="x12">
     >         <div>
     >           <bar id="x13">
     >             <div>
     >               <p/>
     >             </div>
     >           </bar>
     >         </div>
     >       </bar>
     >     </bar>
     >   </bar>
     > </bars>
     >
     >
     > <?xml version="1.0" encoding="UTF-8"?>
     > <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform
    <http://www.w3.org/1999/XSL/Transform>"
    xmlns:xs="http://www.w3.org/2001/XMLSchema
    <http://www.w3.org/2001/XMLSchema>" version="2.0">
     >   <xsl:output method="xml" indent="yes" omit-xml-declaration="no"/>
     >   <xsl:strip-space elements="*"/>
     >
     >   <xsl:template match="p">
     >     <xsl:variable name="topic"
    select="ancestor-or-self::*[@id][1]" as="element()"/>
     >     <xsl:variable name="ancestors-in-topic"
    select="ancestor-or-self::*[ancestor-or-self::*/generate-id() =
    generate-id($topic)]" as="element()*"/>
     >     <xsl:copy>
     >       <xsl:attribute name="topic" select="$topic/@id"/>
     >       <xsl:text>Ancestors: </xsl:text>
     >        <xsl:sequence select="$ancestors-in-topic/name()"/>
     >     </xsl:copy>
     >   </xsl:template>
     >
     >   <xsl:template match="* | @*">
     >     <xsl:copy>
     >       <xsl:apply-templates select="@*, node()"/>
     >     </xsl:copy>
     >   </xsl:template>
     > </xsl:stylesheet>
     >
     >
     > Expected output for <p>: <p topic="x13">Ancestors: bar div p</p>
>

    ---------- Forwarded message ----------
    From: Syd Bauman <s(_dot_)bauman(_at_)northeastern(_dot_)edu
    <mailto:s(_dot_)bauman(_at_)northeastern(_dot_)edu>>
    To: <xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
    <mailto:xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com>>
    Cc:
    Bcc:
    Date: Wed, 30 Aug 2017 15:18:54 -0400
    Subject: Re: [xsl] Can I use xsl:key to select elements up to
    certain ancestor
    I think there may be a more efficient way to do this overall, but
    certainly if you declare those @id attributes as ID, then you could
    use the id() function. E.g.:

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

       <xsl:output method="xml" indent="yes" omit-xml-declaration="no"/>
       <xsl:strip-space elements="*"/>

       <xsl:template match="p">
         <xsl:variable name="topicID"
    select="ancestor-or-self::*[@id][1]/@id"/>
         <xsl:variable name="ancestors-in-topic"
                             select="ancestor-or-self::*[
             ancestor-or-self::* intersect id($topicID)
             ]"/>
         <xsl:copy>
           <xsl:attribute name="topic" select="$topicID"/>
           <xsl:text>Ancestors: </xsl:text>
           <xsl:sequence select="$ancestors-in-topic/name()"/>
         </xsl:copy>
       </xsl:template>

       <xsl:template match="* | @*">
         <xsl:copy>
           <xsl:apply-templates select="@*, node()"/>
         </xsl:copy>
       </xsl:template>

    </xsl:stylesheet>
    ---------

    works iff you declare the @id attrs as type ID:

    ---------
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE bars [
    <!ELEMENT bars ( bar+ )>
    <!ATTLIST bars id ID #IMPLIED>

    <!ELEMENT bar ( bar | div )+>
    <!ATTLIST bar id ID #IMPLIED>

    <!ELEMENT div ( bar | div | p )+>
    <!ELEMENT p EMPTY >
    ]>
    <bars id="x0">
       <bar id="x1">
         <bar id="x11">
           <bar id="x12">
             <div>
               <bar id="x13">
                 <div>
                   <p/>
                 </div>
               </bar>
             </div>
           </bar>
         </bar>
       </bar>
    </bars>
    ---------

     > I had an embarrassing moment today, when I found that the source of
     > a severe performance problem was sitting in front of the screen.
     >
     > Using XSLT 2.0 I am transforming elements and at many points I have
     > to look up the ancestor axis, but only up to an element with an
     > attribute "id". Basically I have a deeply nested structure of
     > topics and I want to analyze ancestors inside the current topic.
     >
     > The nearest topic is easy to find:
     >
     > <xsl:variable name="topic" select="ancestor-or-self::*[@id][1]"
    as="element()"/>
     >
     > And then I was doing the following to find all ancestors that share
     > the same "topic ancestor":
     >
     > <xsl:variable name="ancestors-in-topic"
     >   select="ancestor-or-self::*[ancestor-or-self::* = $topic]"
    as="element()*"/>
     >
     > This did not what I expected and also wasted a lot of resources
     > because the predicate was true for all or most elements. After some
     > testing I went with this:
     >
     > <xsl:variable name="ancestors-in-topic"
     >   select="ancestor-or-self::*[ancestor-or-self::*/generate-id() =
    generate-id($topic)]" as="element()*"/>
     >
     > Since that calculation is done very often I am wondering if xsl:key
     > could be used to speed things up?
     >
     > Any pointers are very welcome, as always, thanks,
     >
     > - Michael
     >
     > PS: My sample XML and XSLT below.
     >
     > <?xml version="1.0" encoding="UTF-8"?>
     > <bars id="x0">
     >   <bar id="x1">
     >     <bar id="x11">
     >       <bar id="x12">
     >         <div>
     >           <bar id="x13">
     >             <div>
     >               <p/>
     >             </div>
     >           </bar>
     >         </div>
     >       </bar>
     >     </bar>
     >   </bar>
     > </bars>
     >
     >
     > <?xml version="1.0" encoding="UTF-8"?>
     > <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform
    <http://www.w3.org/1999/XSL/Transform>"
    xmlns:xs="http://www.w3.org/2001/XMLSchema
    <http://www.w3.org/2001/XMLSchema>" version="2.0">
     >   <xsl:output method="xml" indent="yes" omit-xml-declaration="no"/>
     >   <xsl:strip-space elements="*"/>
     >
     >   <xsl:template match="p">
     >     <xsl:variable name="topic"
    select="ancestor-or-self::*[@id][1]" as="element()"/>
     >     <xsl:variable name="ancestors-in-topic"
    select="ancestor-or-self::*[ancestor-or-self::*/generate-id() =
    generate-id($topic)]" as="element()*"/>
     >     <xsl:copy>
     >       <xsl:attribute name="topic" select="$topic/@id"/>
     >       <xsl:text>Ancestors: </xsl:text>
     >        <xsl:sequence select="$ancestors-in-topic/name()"/>
     >     </xsl:copy>
     >   </xsl:template>
     >
     >   <xsl:template match="* | @*">
     >     <xsl:copy>
     >       <xsl:apply-templates select="@*, node()"/>
     >     </xsl:copy>
     >   </xsl:template>
     > </xsl:stylesheet>
     >
     >
     > Expected output for <p>: <p topic="x13">Ancestors: bar div p</p>
>
    --
      Syd Bauman, EMT-Paramedic
      Senior XML Programmer/Analyst
      Northeastern University Women Writers Project
    s(_dot_)bauman(_at_)northeastern(_dot_)edu 
<mailto:s(_dot_)bauman(_at_)northeastern(_dot_)edu> or
    Syd_Bauman(_at_)alumni(_dot_)Brown(_dot_)edu 
<mailto:Syd_Bauman(_at_)alumni(_dot_)Brown(_dot_)edu>



    ---------- Forwarded message ----------
    From: Wolfgang Laun <wolfgang(_dot_)laun(_at_)gmail(_dot_)com
    <mailto:wolfgang(_dot_)laun(_at_)gmail(_dot_)com>>
    To: xsl-list <xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
    <mailto:xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com>>
    Cc:
    Bcc:
    Date: Wed, 30 Aug 2017 21:24:01 +0200
    Subject: Re: [xsl] Can I use xsl:key to select elements up to
    certain ancestor
    Wouldn't assigning any element with an @id to a temporaty document
    and running rules against this reduce the overhead?
    -W

    On 30 August 2017 at 21:08, David Carlisle 
d(_dot_)p(_dot_)carlisle(_at_)gmail(_dot_)com
    <mailto:d(_dot_)p(_dot_)carlisle(_at_)gmail(_dot_)com>
    <xsl-list-service(_at_)lists(_dot_)mulberrytech(_dot_)com
    <mailto:xsl-list-service(_at_)lists(_dot_)mulberrytech(_dot_)com>> wrote:

        You seem to be listing ancestor-or-self rather than ancestor, I
        think
        you only need to go up the ancestor axis once in each case,
        something
        like

        <xsl:stylesheet version="2.0"
                 xmlns:xsl="http://www.w3.org/1999/XSL/Transform
        <http://www.w3.org/1999/XSL/Transform>">


          <xsl:template match="/">
           <xsl:apply-templates select="//p"/><!-- just for testing-->
          </xsl:template>


          <xsl:template match="*">
           <xsl:copy>
            <xsl:apply-templates select="." mode="a"/>
           </xsl:copy>
          </xsl:template>

          <xsl:template match="*" mode="a">
           <xsl:param name="trail" select="()"/>
           <xsl:apply-templates select="parent::*" mode="a">
            <xsl:with-param name="trail" select="name(),$trail"/>
           </xsl:apply-templates>
          </xsl:template>

          <xsl:template match="*[@id]" mode="a">
           <xsl:param name="trail" select="()"/>
            <xsl:copy-of select="@id,'Ancestors:', name(), $trail"/>
          </xsl:template>

        </xsl:stylesheet>


        which makes


        <p id="x13">Ancestors: bar div p</p>

        On 30 August 2017 at 19:49, Michael Müller-Hillebrand
        mmh(_at_)docufy(_dot_)de <mailto:mmh(_at_)docufy(_dot_)de>
        <xsl-list-service(_at_)lists(_dot_)mulberrytech(_dot_)com
        <mailto:xsl-list-service(_at_)lists(_dot_)mulberrytech(_dot_)com>> 
wrote:
         > Hi all,
         >
         > I had an embarrassing moment today, when I found that the
        source of a severe performance problem was sitting in front of
        the screen.
         >
         > Using XSLT 2.0 I am transforming elements and at many points
        I have to look up the ancestor axis, but only up to an element
        with an attribute "id". Basically I have a deeply nested
        structure of topics and I want to analyze ancestors inside the
        current topic.
         >
         > The nearest topic is easy to find:
         >
         > <xsl:variable name="topic"
        select="ancestor-or-self::*[@id][1]" as="element()"/>
         >
         > And then I was doing the following to find all ancestors that
        share the same "topic ancestor":
         >
         > <xsl:variable name="ancestors-in-topic"
         >   select="ancestor-or-self::*[ancestor-or-self::* = $topic]"
        as="element()*"/>
         >
         > This did not what I expected and also wasted a lot of
        resources because the predicate was true for all or most
        elements. After some testing I went with this:
         >
         > <xsl:variable name="ancestors-in-topic"
>  select="ancestor-or-self::*[ancestor-or-self::*/generate-id()
        = generate-id($topic)]" as="element()*"/>
         >
         > Since that calculation is done very often I am wondering if
        xsl:key could be used to speed things up?
         >
         > Any pointers are very welcome, as always, thanks,
         >
         > - Michael
         >
         > PS: My sample XML and XSLT below.
         >
         > <?xml version="1.0" encoding="UTF-8"?>
         > <bars id="x0">
         >   <bar id="x1">
         >     <bar id="x11">
         >       <bar id="x12">
         >         <div>
         >           <bar id="x13">
         >             <div>
         >               <p/>
         >             </div>
         >           </bar>
         >         </div>
         >       </bar>
         >     </bar>
         >   </bar>
         > </bars>
         >
         >
         > <?xml version="1.0" encoding="UTF-8"?>
         > <xsl:stylesheet
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform
        <http://www.w3.org/1999/XSL/Transform>"
        xmlns:xs="http://www.w3.org/2001/XMLSchema
        <http://www.w3.org/2001/XMLSchema>" version="2.0">
         >   <xsl:output method="xml" indent="yes"
        omit-xml-declaration="no"/>
         >   <xsl:strip-space elements="*"/>
         >
         >   <xsl:template match="p">
         >     <xsl:variable name="topic"
        select="ancestor-or-self::*[@id][1]" as="element()"/>
         >     <xsl:variable name="ancestors-in-topic"
        select="ancestor-or-self::*[ancestor-or-self::*/generate-id() =
        generate-id($topic)]" as="element()*"/>
         >     <xsl:copy>
         >       <xsl:attribute name="topic" select="$topic/@id"/>
         >       <xsl:text>Ancestors: </xsl:text>
         >        <xsl:sequence select="$ancestors-in-topic/name()"/>
         >     </xsl:copy>
         >   </xsl:template>
         >
         >   <xsl:template match="* | @*">
         >     <xsl:copy>
         >       <xsl:apply-templates select="@*, node()"/>
         >     </xsl:copy>
         >   </xsl:template>
         > </xsl:stylesheet>
         >
         >
         > Expected output for <p>: <p topic="x13">Ancestors: bar div p</p>
         >



    ---------- Forwarded message ----------
    From: Michael Kay <mike(_at_)saxonica(_dot_)com 
<mailto:mike(_at_)saxonica(_dot_)com>>
    To: xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
    <mailto:xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com>
    Cc:
    Bcc:
    Date: Wed, 30 Aug 2017 23:19:45 +0100
    Subject: Re: [xsl] Can I use xsl:key to select elements up to
    certain ancestor
     >
     > And then I was doing the following to find all ancestors that
    share the same "topic ancestor":
     >
     > <xsl:variable name="ancestors-in-topic"
     >  select="ancestor-or-self::*[ancestor-or-self::* = $topic]"
    as="element()*"/>
     >
     > This did not what I expected and also wasted a lot of resources
    because the predicate was true for all or most elements. After some
    testing I went with this:
     >
     > <xsl:variable name="ancestors-in-topic"
     >  select="ancestor-or-self::*[ancestor-or-self::*/generate-id() =
    generate-id($topic)]" as="element()*"/>

    You're looking for ancestors of the context item that are
    descendants of $topic (with a possible -or-self thrown in).

    The challenge here is to avoid making this quadratic in the length
    of the ancestor axis. Your code is effectively saying "for every
    ancestor, find every ancestor and test it".

    Use of the "=" operator is a bad mistake: this compares string
    values of nodes, which involves examining all the descendants: it's
    not only inefficient, it also gives the wrong answer.

    I think the simplest solution is (ancestor-or-self::* except
    $topic/ancestor::*) but this is still rather inefficient (it will
    also return nodes in document order so you may need to reverse() the
    result). I've often wished there was an "until" operator in XPath
    that selects all items in a sequence up to the first where a
    condition is true:

    ancestor-or-self::* until (self::* is $topic)

    and you can write this yourself as a higher-order extension function
    in 3.0:

    <xsl:function name="f:until" as="item()*">
       <xsl:param name="seq" as="item()*"/>
       <xsl:param name="condition" as="function(item()) as xs:boolean"/>
       <xsl:sequence select="
          if (empty($seq))
          then ()
          else if ($condition(head($seq))
          then head($seq)
          else (head($seq), f:until(tail($seq), $condition))"/>
    </xsl:function>

    and you could invoke this as

    f:until(ancestor-or-self::*, function($x){$x is $topic})

    Of course you could also write a less generic recursive function:

    <xsl:function name="nodes-until" as="item()*">
       <xsl:param name="seq" as="item()*"/>
       <xsl:param name="target" as="node()"/>
       <xsl:sequence select="
          if (empty($seq))
          then ()
          else if ($target is head($seq))
          then head($seq)
          else (head($seq), nodes-until(tail($seq), $target))"/>
    </xsl:function>

    f:nodes-until(ancestor::*, $topic)

    Michael Kay
    Saxonica


     > <xsl:variable name="ancestors-in-topic"
     >  select="ancestor-or-self::*[some $ancestor-or-self::* is
    $topic)]" as="element()*"/>


     >
     > Since that calculation is done very often I am wondering if
    xsl:key could be used to speed things up?
     >
     > Any pointers are very welcome, as always, thanks,
     >
     > - Michael
     >
     > PS: My sample XML and XSLT below.
     >
     > <?xml version="1.0" encoding="UTF-8"?>
     > <bars id="x0">
     >  <bar id="x1">
     >    <bar id="x11">
     >      <bar id="x12">
     >        <div>
     >          <bar id="x13">
     >            <div>
     >              <p/>
     >            </div>
     >          </bar>
     >        </div>
     >      </bar>
     >    </bar>
     >  </bar>
     > </bars>
     >
     >
     > <?xml version="1.0" encoding="UTF-8"?>
     > <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform
    <http://www.w3.org/1999/XSL/Transform>"
    xmlns:xs="http://www.w3.org/2001/XMLSchema
    <http://www.w3.org/2001/XMLSchema>" version="2.0">
     >  <xsl:output method="xml" indent="yes" omit-xml-declaration="no"/>
     >  <xsl:strip-space elements="*"/>
     >
     >  <xsl:template match="p">
     >    <xsl:variable name="topic"
    select="ancestor-or-self::*[@id][1]" as="element()"/>
     >    <xsl:variable name="ancestors-in-topic"
    select="ancestor-or-self::*[ancestor-or-self::*/generate-id() =
    generate-id($topic)]" as="element()*"/>
     >    <xsl:copy>
     >      <xsl:attribute name="topic" select="$topic/@id"/>
     >      <xsl:text>Ancestors: </xsl:text>
     >       <xsl:sequence select="$ancestors-in-topic/name()"/>
     >    </xsl:copy>
     >  </xsl:template>
     >
     >  <xsl:template match="* | @*">
     >    <xsl:copy>
     >      <xsl:apply-templates select="@*, node()"/>
     >    </xsl:copy>
     >  </xsl:template>
     > </xsl:stylesheet>
     >
     >
     > Expected output for <p>: <p topic="x13">Ancestors: bar div p</p>
>


    ---------- Forwarded message ----------
    From: Rahul Singh <rahulsinghindia15(_at_)gmail(_dot_)com
    <mailto:rahulsinghindia15(_at_)gmail(_dot_)com>>
    To: xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
    <mailto:xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com>, "XSL-List: The 
Open Forum
    on XSL" <xsl-list-service(_at_)lists(_dot_)mulberrytech(_dot_)com
    <mailto:xsl-list-service(_at_)lists(_dot_)mulberrytech(_dot_)com>>
    Cc:
    Bcc:
    Date: Thu, 31 Aug 2017 08:57:33 +0530
    Subject: XSL matching and duplication!
    Hi,

    i need data from input1.xml check first if clientname/id is matching
    with clientdata/name from input2.xml otherwise delete duplication
    based on clientname/Email from input1.xml, My duplication is working
    but i am not geetitng first condition data:

    <xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform
    <http://www.w3.org/1999/XSL/Transform>">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>
    <xsl:key name="kBymail" match="clientname" use="Email"/>
    <xsl:template match="node() | @*">
    <xsl:copy>
    <xsl:apply-templates select="node() | @*"/>
    </xsl:copy>
    </xsl:template>
    <xsl:template match="clientname[Email =
    following-sibling::clientname/Email]"/>
    </xsl:stylesheet>

    Input1.xml:
    ------------------------------------------------
    <?xml version="1.0" encoding="UTF-8"?>
    <ClientInfo>
        <clientname>
             <Id>003f40000049yJYAAY</Id>
             <Email>gbc(_at_)gmail(_dot_)com 
<mailto:gbc(_at_)gmail(_dot_)com></Email>
          </clientname>
        <clientname>
             <Id>003f40000049z3iAAA</Id>
             <Email>gbc(_at_)gmail(_dot_)com 
<mailto:gbc(_at_)gmail(_dot_)com></Email>
          </clientname>
        <clientname>
             <Id>003f40000049z3nAAA</Id>
             <Email>gbc(_at_)gmail(_dot_)com 
<mailto:gbc(_at_)gmail(_dot_)com></Email>
          </clientname>
        <clientname>
             <Id>003f40000048uLLAAY</Id>
             <Email>gar(_at_)gmail(_dot_)com 
<mailto:gar(_at_)gmail(_dot_)com></Email>
          </clientname>
        <clientname>
             <Id>003f40000049t38AAA</Id>
             <Email>gad(_at_)gmail(_dot_)com 
<mailto:gad(_at_)gmail(_dot_)com></Email>
          </clientname>
       </objects>

    Input2.xml:
    ---------------------------------------
       <?xml version="1.0" encoding="UTF-8"?>
    <ClientInfo>
        <clientdata>
             <name>003f40000048uLLAAY</name>
           <clientnameReference>
                <Email>gar(_at_)gmail(_dot_)com 
<mailto:gar(_at_)gmail(_dot_)com></Email>
             </clientnameReference>
          </clientdata>
        <clientdata>
             <name>003f40000049t38AAA</name>
           <clientnameReference>
                <Email>gad(_at_)gmail(_dot_)com 
<mailto:gad(_at_)gmail(_dot_)com></Email>
             </clientnameReference>
          </clientdata>
        <clientdata>
             <name>003f40000049yJYAAY</name>
           <clientnameReference>
                <Email>gbc(_at_)gmail(_dot_)com 
<mailto:gbc(_at_)gmail(_dot_)com></Email>
             </clientnameReference>
          </clientdata>
       </objects>


    Expectedoutput:
    ---------------------------------------
    <?xml version="1.0" encoding="UTF-8"?>
    <ClientInfo>
        <clientname>
             <Id>003f40000049yJYAAY</Id>
             <Name>barcode11</Name>
             <Email>gbc(_at_)gmail(_dot_)com 
<mailto:gbc(_at_)gmail(_dot_)com></Email>
          </clientname>
        <clientname>
             <Id>003f40000048uLLAAY</Id>
             <Name>Bob Robben</Name>
             <Email>gar(_at_)gmail(_dot_)com 
<mailto:gar(_at_)gmail(_dot_)com></Email>
          </clientname>
        <clientname>
             <Id>003f40000049t38AAA</Id>
             <Name>ADVT4</Name>
             <Email>gad(_at_)gmail(_dot_)com 
<mailto:gad(_at_)gmail(_dot_)com></Email>
          </clientname>
       </objects>



    ---------- Forwarded message ----------
    From: "Imsieke, Gerrit, le-tex" <gerrit(_dot_)imsieke(_at_)le-tex(_dot_)de
    <mailto:gerrit(_dot_)imsieke(_at_)le-tex(_dot_)de>>
    To: xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
    <mailto:xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com>
    Cc:
    Bcc:
    Date: Thu, 31 Aug 2017 08:01:05 +0200
    Subject: Re: [xsl] XSL matching and duplication!
    Hi Rahul,

    A couple of observations/questions:

    – Assuming that you invoke the transformation with Input1.xml as the
    source, how does the stylesheet ever get to know Input2.xml in order
    to do any comparisons with clientdata/name? If Input1.xml is the
    input, I would have expected something like <xsl:variable
    name="Input2" as="document-node(element(ClientInfo))"
    select="doc('Input2.xml')"/> in the stylesheet.

    – What exactly should happen if clientname/Id of Input1.xml matches
    clientdata/name of Input2.xml, and what should happen if it doesn’t?
    In particular, the records of which file should be de-duplicated,
    Input1.xml’s clientname records or Input2.xml? Your expected output
    suggests that Input1.xml’s records should be de-duplicated.
    What should happen if there is no match for clientdata/name in
    Input2.xml? As I understood the requirement, then no de-duplication
    should occur. I’m not sure whether this is your intention.

    – Finally, where do the Name fields stem from in the expected
    output? They are not present in any of the inputs.

    These are the essential questions. In addition, a couple of other
    things did not go unnoticed:

    – You declare a key named 'kBymail', but you don’t use it.

    – The start and end tags of the top-level elements in Input1.xml and
    Input2.xml don’t match.

    – You are comparing the clientname/Email element with the Email
    element of all following siblings. This can become a performance
    issue for large data sets. Consider using <xsl:for-each-group
    select="clientname" group-by="Email"> for de-duplication.

    Gerrit



    On 31.08.2017 05:27, Rahul Singh rahulsinghindia15(_at_)gmail(_dot_)com
    <mailto:rahulsinghindia15(_at_)gmail(_dot_)com> wrote:

        Hi,

        i need data from input1.xml check first if clientname/id is
        matching with clientdata/name from input2.xml otherwise delete
        duplication based on clientname/Email from input1.xml, My
        duplication is working but i am not geetitng first condition data:

        <xsl:stylesheet version="2.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform
        <http://www.w3.org/1999/XSL/Transform>">
        <xsl:output omit-xml-declaration="yes" indent="yes"/>
        <xsl:strip-space elements="*"/>
        <xsl:key name="kBymail" match="clientname" use="Email"/>
        <xsl:template match="node() | @*">
        <xsl:copy>
        <xsl:apply-templates select="node() | @*"/>
        </xsl:copy>
        </xsl:template>
        <xsl:template match="clientname[Email =
        following-sibling::clientname/Email]"/>
        </xsl:stylesheet>

        Input1.xml:
        ------------------------------------------------
        <?xml version="1.0" encoding="UTF-8"?>
        <ClientInfo>
             <clientname>
                  <Id>003f40000049yJYAAY</Id>
                  <Email>gbc(_at_)gmail(_dot_)com 
<mailto:gbc(_at_)gmail(_dot_)com>
        <mailto:gbc(_at_)gmail(_dot_)com 
<mailto:gbc(_at_)gmail(_dot_)com>></Email>
               </clientname>
             <clientname>
                  <Id>003f40000049z3iAAA</Id>
                  <Email>gbc(_at_)gmail(_dot_)com 
<mailto:gbc(_at_)gmail(_dot_)com>
        <mailto:gbc(_at_)gmail(_dot_)com 
<mailto:gbc(_at_)gmail(_dot_)com>></Email>
               </clientname>
             <clientname>
                  <Id>003f40000049z3nAAA</Id>
                  <Email>gbc(_at_)gmail(_dot_)com 
<mailto:gbc(_at_)gmail(_dot_)com>
        <mailto:gbc(_at_)gmail(_dot_)com 
<mailto:gbc(_at_)gmail(_dot_)com>></Email>
               </clientname>
             <clientname>
                  <Id>003f40000048uLLAAY</Id>
                  <Email>gar(_at_)gmail(_dot_)com 
<mailto:gar(_at_)gmail(_dot_)com>
        <mailto:gar(_at_)gmail(_dot_)com 
<mailto:gar(_at_)gmail(_dot_)com>></Email>
               </clientname>
             <clientname>
                  <Id>003f40000049t38AAA</Id>
                  <Email>gad(_at_)gmail(_dot_)com 
<mailto:gad(_at_)gmail(_dot_)com>
        <mailto:gad(_at_)gmail(_dot_)com 
<mailto:gad(_at_)gmail(_dot_)com>></Email>
               </clientname>
            </objects>

        Input2.xml:
        ---------------------------------------
            <?xml version="1.0" encoding="UTF-8"?>
        <ClientInfo>
             <clientdata>
                  <name>003f40000048uLLAAY</name>
                <clientnameReference>
                     <Email>gar(_at_)gmail(_dot_)com 
<mailto:gar(_at_)gmail(_dot_)com>
        <mailto:gar(_at_)gmail(_dot_)com 
<mailto:gar(_at_)gmail(_dot_)com>></Email>
                  </clientnameReference>
               </clientdata>
             <clientdata>
                  <name>003f40000049t38AAA</name>
                <clientnameReference>
                     <Email>gad(_at_)gmail(_dot_)com 
<mailto:gad(_at_)gmail(_dot_)com>
        <mailto:gad(_at_)gmail(_dot_)com 
<mailto:gad(_at_)gmail(_dot_)com>></Email>
                  </clientnameReference>
               </clientdata>
             <clientdata>
                  <name>003f40000049yJYAAY</name>
                <clientnameReference>
                     <Email>gbc(_at_)gmail(_dot_)com 
<mailto:gbc(_at_)gmail(_dot_)com>
        <mailto:gbc(_at_)gmail(_dot_)com 
<mailto:gbc(_at_)gmail(_dot_)com>></Email>
                  </clientnameReference>
               </clientdata>
            </objects>


        Expectedoutput:
        ---------------------------------------
        <?xml version="1.0" encoding="UTF-8"?>
        <ClientInfo>
             <clientname>
                  <Id>003f40000049yJYAAY</Id>
                  <Name>barcode11</Name>
                  <Email>gbc(_at_)gmail(_dot_)com 
<mailto:gbc(_at_)gmail(_dot_)com>
        <mailto:gbc(_at_)gmail(_dot_)com 
<mailto:gbc(_at_)gmail(_dot_)com>></Email>
               </clientname>
             <clientname>
                  <Id>003f40000048uLLAAY</Id>
                  <Name>Bob Robben</Name>
                  <Email>gar(_at_)gmail(_dot_)com 
<mailto:gar(_at_)gmail(_dot_)com>
        <mailto:gar(_at_)gmail(_dot_)com 
<mailto:gar(_at_)gmail(_dot_)com>></Email>
               </clientname>
             <clientname>
                  <Id>003f40000049t38AAA</Id>
                  <Name>ADVT4</Name>
                  <Email>gad(_at_)gmail(_dot_)com 
<mailto:gad(_at_)gmail(_dot_)com>
        <mailto:gad(_at_)gmail(_dot_)com 
<mailto:gad(_at_)gmail(_dot_)com>></Email>
               </clientname>
            </objects>

        XSL-List info and archive
        <http://www.mulberrytech.com/xsl/xsl-list
        <http://www.mulberrytech.com/xsl/xsl-list>>
        EasyUnsubscribe
        <-list/225679
        <-list/225679>> (by email
        <
        <>?subject=remove>)


-- Gerrit Imsieke
    Geschäftsführer / Managing Director
    le-tex publishing services GmbH
    Weissenfelser Str. 84, 04229 Leipzig, Germany
    Phone +49 341 355356 110, Fax +49 341 355356 510
    gerrit(_dot_)imsieke(_at_)le-tex(_dot_)de 
<mailto:gerrit(_dot_)imsieke(_at_)le-tex(_dot_)de>,
    http://www.le-tex.de

    Registergericht / Commercial Register: Amtsgericht Leipzig
    Registernummer / Registration Number: HRB 24930

    Geschäftsführer: Gerrit Imsieke, Svea Jelonek,
    Thomas Schmidt, Dr. Reinhard Vöckler



--
Gerrit Imsieke
Geschäftsführer / Managing Director
le-tex publishing services GmbH
Weissenfelser Str. 84, 04229 Leipzig, Germany
Phone +49 341 355356 110, Fax +49 341 355356 510
gerrit(_dot_)imsieke(_at_)le-tex(_dot_)de, http://www.le-tex.de

Registergericht / Commercial Register: Amtsgericht Leipzig
Registernummer / Registration Number: HRB 24930

Geschäftsführer: Gerrit Imsieke, Svea Jelonek,
Thomas Schmidt, Dr. Reinhard Vöckler
--~----------------------------------------------------------------
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>
  • [xsl] Re: [XSL-List: The Open Forum on XSL] Digest for 2017-08-30, Imsieke, Gerrit, le-tex gerrit(_dot_)imsieke(_at_)le-tex(_dot_)de <=