[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 <=
|
|
|