473,406 Members | 2,467 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,406 software developers and data experts.

search for maximum hierarchy

Dear All,

may be some of you can help me with an XSLT example how to solve the
following challange.
For the XML below I want to find out the maximum hierarchy level for a
specific element in my XSLT. The result for the example (searching for
<A/>) should be 4 as the element A is nested 4 times maximum.
I guess I have to use somehow the count function with 'following::A'
axes. But I could not get that to work yet.

Thanks a lot for your help
Rolf

<ROOT>
<A>
<A>
<B>
<C>
<A/> nested up to 3
</C>
</B>
</A>
<A>
<B>
<C>
<A>
<A/> nested up to 4
</A>
<C>
</B>
</A>
</A>
</ROOT>
Jul 20 '05 #1
10 2067
Ke*****@t-online.de (KemperR) writes:
may be some of you can help me with an XSLT example how to solve the
following challange.
For the XML below I want to find out the maximum hierarchy level for a
specific element in my XSLT. The result for the example (searching for
<A/>) should be 4 as the element A is nested 4 times maximum.
I guess I have to use somehow the count function with 'following::A'
axes. But I could not get that to work yet.


Hmmm. I found this surprisingly tricky to do. The solution looks
complex, but the bulk of it is just a recursive template for finding
the maximum of a list of numbers.

This does the job:

----XML---- (your xml corrected)
<ROOT>
<A>
<A>
<B>
<C>
<A/>
</C>
</B>
</A>
<A>
<B>
<C>
<A>
<A/>
</A>
</C>
</B>
</A>
</A>
</ROOT>

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

<xsl:template match="/">
<xsl:call-template name="max">
<xsl:with-param name="data">
<!-- We construct a list of local-maximum tree-depths -->
<xsl:for-each select="//*[not(child::*)]">
<xsl:value-of select="count(ancestor::*)"/>
<xsl:text>:</xsl:text>
</xsl:for-each>
</xsl:with-param>
<xsl:with-param name="max" select="0"/>
</xsl:call-template>
</xsl:template>

<xsl:template name="max">
<xsl:param name="data"/>
<xsl:param name="max"/>
<xsl:choose>
<xsl:when test="$data">
<xsl:variable name="current"
select="number(substring-before($data,':'))"/>
<xsl:call-template name="max">
<xsl:with-param name="data"
select="substring-after($data,':')"/>
<xsl:with-param name="max">
<xsl:choose>
<xsl:when test="$current>$max">
<xsl:value-of select="$current"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$max"/>
</xsl:otherwise>
</xsl:choose>
</xsl:with-param>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$max"/>
</xsl:otherwise>
</xsl:choose>

</xsl:template>

</xsl:stylesheet>

----Ouput----
<?xml version="1.0"?>
6
If you want to get "4" (for your definition of nesting) then change
the line
<xsl:value-of select="$max"/>
to
<xsl:value-of select="$max - 2"/>

Ben
--
Ben Edgington
Mail to the address above is discarded.
Mail to ben at that address might be read.
http://www.edginet.org/
Jul 20 '05 #2
Ben Edgington <us****@edginet.org> writes:
Ke*****@t-online.de (KemperR) writes:
may be some of you can help me with an XSLT example how to solve the
following challange.
For the XML below I want to find out the maximum hierarchy level for a
specific element in my XSLT. The result for the example (searching for
<A/>) should be 4 as the element A is nested 4 times maximum.
I guess I have to use somehow the count function with 'following::A'
axes. But I could not get that to work yet.


Hmmm. I found this surprisingly tricky to do. The solution looks
complex, but the bulk of it is just a recursive template for finding
the maximum of a list of numbers.


Now I've actually read your question here's a slightly amended
stylesheet that does what you want 8^). I've only changed the two
XPath expressions near the top to use 'A' instead of '*', and added
one to the output of $max (so that the current 'A' element is included
in the count).

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

<xsl:template match="/">

<xsl:call-template name="max">
<xsl:with-param name="data">
<xsl:for-each select="//A[not(child::*)]">
<xsl:value-of select="count(ancestor::A)"/>
<xsl:text>:</xsl:text>
</xsl:for-each>
</xsl:with-param>
<xsl:with-param name="max" select="0"/>
</xsl:call-template>
</xsl:template>

<xsl:template name="max">
<xsl:param name="data"/>
<xsl:param name="max"/>
<xsl:choose>
<xsl:when test="$data">
<xsl:variable name="current"
select="number(substring-before($data,':'))"/>
<xsl:call-template name="max">
<xsl:with-param name="data"
select="substring-after($data,':')"/>
<xsl:with-param name="max">
<xsl:choose>
<xsl:when test="$current>$max">
<xsl:value-of select="$current"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$max"/>
</xsl:otherwise>
</xsl:choose>
</xsl:with-param>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$max+1"/>
</xsl:otherwise>
</xsl:choose>

</xsl:template>

</xsl:stylesheet>

--
Ben Edgington
Mail to the address above is discarded.
Mail to ben at that address might be read.
http://www.edginet.org/
Jul 20 '05 #3
Ben Edgington wrote:
Hmmm. I found this surprisingly tricky to do. The solution looks
complex, but the bulk of it is just a recursive template for finding
the maximum of a list of numbers.


Yes, this is not as easy as it looks at first sight.
An interesting example because it puts XSL's mechanisms
to the test. Here is a solution in xmlgawk which I
find much more readable than XSL.

# depth.awk
# Reads an XML document from standard input and
# prints a count value to standard output. The
# count value tells us how deep each kind of
# element is nested inside each other, neglecting
# nesting levels of other elements.
# comp.text.xml 2004-09-09
# JK 2004-09-09

BEGIN { XMLMODE=1 }

# For each element, increase the depth and find
# the maximum of the nesting depths for each element.
XMLSTARTELEM {
nest[XMLSTARTELEM] ++
if (nest[XMLSTARTELEM] > maxdepth[XMLSTARTELEM])
maxdepth[XMLSTARTELEM] = nest[XMLSTARTELEM]
}

# When leaving an element, decrease nesting depth.
XMLENDELEM {
nest[XMLENDELEM] --
}

# Print maximum depth for each kind of element.
END {
for (elem in maxdepth)
print elem, ":", maxdepth[elem]
}
This is the result for the XML data given in your
corrected version:

A : 4
B : 1
C : 1
ROOT : 1

Jul 20 '05 #4
Hi,

Using <xsl:for-each> and sorting method of finding a max, something like...

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:variable name="max-A">
<xsl:for-each select="//A">
<xsl:sort select="count(.| ancestor::A)" data-type="number"
order="descending"/>
<xsl:if test="position() = 1">
<xsl:value-of select="count(.| ancestor::A)"/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:text>Max nesting of &lt;A&gt; is: </xsl:text>
<xsl:value-of select="$max-A"/>
</xsl:template>
</xsl:stylesheet>

Using recursion, something like...

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>

<xsl:template match="/">
<xsl:variable name="max-A">
<xsl:apply-templates select="(//A)[1]"/>
</xsl:variable>
<xsl:text>Max nesting of &lt;A&gt; is: </xsl:text>
<xsl:value-of select="$max-A"/>
</xsl:template>

<xsl:template match="A">
<xsl:param name="max" select="0"/>
<xsl:variable name="this-max" select="count(. | ancestor::A)"/>
<xsl:variable name="new-max" select="($max * number($this-max &lt;= $max))
+ ($this-max * number($this-max &gt; $max))"/>
<xsl:choose>
<xsl:when test="following::A | descendant::A">
<xsl:apply-templates select="(following::A | descendant::A)[1]">
<xsl:with-param name="max" select="$new-max"/>
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$new-max"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
HTH
Marrow
http://www.marrowsoft.com - home of Xselerator (XSLT IDE and debugger)
http://www.topxml.com/Xselerator
"KemperR" <Ke*****@t-online.de> wrote in message
news:90**************************@posting.google.c om...
Dear All,

may be some of you can help me with an XSLT example how to solve the
following challange.
For the XML below I want to find out the maximum hierarchy level for a
specific element in my XSLT. The result for the example (searching for
<A/>) should be 4 as the element A is nested 4 times maximum.
I guess I have to use somehow the count function with 'following::A'
axes. But I could not get that to work yet.

Thanks a lot for your help
Rolf

<ROOT>
<A>
<A>
<B>
<C>
<A/> nested up to 3
</C>
</B>
</A>
<A>
<B>
<C>
<A>
<A/> nested up to 4
</A>
<C>
</B>
</A>
</A>
</ROOT>

Jul 20 '05 #5
Dear Ben,

thanks for the code !!

It works fine, but I'm really surprised how complex it is to get this
actually easy information.

Rolf

Ben Edgington <us****@edginet.org> wrote in message news:<87************@edginet.org>...
Ben Edgington <us****@edginet.org> writes:
Ke*****@t-online.de (KemperR) writes:
may be some of you can help me with an XSLT example how to solve the
following challange.
For the XML below I want to find out the maximum hierarchy level for a
specific element in my XSLT. The result for the example (searching for
<A/>) should be 4 as the element A is nested 4 times maximum.
I guess I have to use somehow the count function with 'following::A'
axes. But I could not get that to work yet.


Hmmm. I found this surprisingly tricky to do. The solution looks
complex, but the bulk of it is just a recursive template for finding
the maximum of a list of numbers.


Now I've actually read your question here's a slightly amended
stylesheet that does what you want 8^). I've only changed the two
XPath expressions near the top to use 'A' instead of '*', and added
one to the output of $max (so that the current 'A' element is included
in the count).

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

<xsl:template match="/">

<xsl:call-template name="max">
<xsl:with-param name="data">
<xsl:for-each select="//A[not(child::*)]">
<xsl:value-of select="count(ancestor::A)"/>
<xsl:text>:</xsl:text>
</xsl:for-each>
</xsl:with-param>
<xsl:with-param name="max" select="0"/>
</xsl:call-template>
</xsl:template>

<xsl:template name="max">
<xsl:param name="data"/>
<xsl:param name="max"/>
<xsl:choose>
<xsl:when test="$data">
<xsl:variable name="current"
select="number(substring-before($data,':'))"/>
<xsl:call-template name="max">
<xsl:with-param name="data"
select="substring-after($data,':')"/>
<xsl:with-param name="max">
<xsl:choose>
<xsl:when test="$current>$max">
<xsl:value-of select="$current"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$max"/>
</xsl:otherwise>
</xsl:choose>
</xsl:with-param>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$max+1"/>
</xsl:otherwise>
</xsl:choose>

</xsl:template>

</xsl:stylesheet>

Jul 20 '05 #6
Rolf Kemper wrote:
It works fine, but I'm really surprised how complex it is to get this
actually easy information.


The complexity comes mostly from the kind of
tool you choose (XSL). There are tools capable
of solving the problem in a more evident way.
I have posted an easier and more general solution.

If the problem to solve was to open a can of
Coca Cola, and your only tool was a hammer,
you would certainly be prepared to face some mess.
Jul 20 '05 #7
KemperR <Ke*****@t-online.de> wrote:
Dear All,

may be some of you can help me with an XSLT example how to solve the
following challange.
For the XML below I want to find out the maximum hierarchy level for a
specific element in my XSLT. The result for the example (searching for
<A/>) should be 4 as the element A is nested 4 times maximum.
I guess I have to use somehow the count function with 'following::A'
axes. But I could not get that to work yet.

Thanks a lot for your help
Rolf

<ROOT>
<A>
<A>
<B>
<C>
<A/> nested up to 3
</C>
</B>
</A>
<A>
<B>
<C>
<A>
<A/> nested up to 4
</A>
<C>
</B>
</A>
</A>
</ROOT>

You had XSL and xmlgawk solution. Here is Bash shell solution:

start () { # Usage: start tag att=value ...
count=`echo ${XML_ELEMENT_STACK[*]|/$1} | wc -w`
[[ count -gt $1 ]] && eval $1=`echo $count`
}
xml -s start "<ROOT>...</ROOT>"
declare -p A B C

Explanation:
- ${...|/glob} returns all array element matching 'glob' pattern.
In this case, 'A', 'B', 'C'.
- if count is greater than previous value, set variable 'A', 'B', or
'C' to that value. This is similar to testing for "max".
- `echo $count` is needed to strip leading whitespaces put there by
'wc -w'.

Ref:
http://freshmeat.net/projects/bashdiff/
http://home.eol.ca/~parkw/index.html#xml
help xml

--
William Park <op**********@yahoo.ca>
Open Geometry Consulting, Toronto, Canada
Jul 20 '05 #8


A shorter, if not necessarily more efficient version os:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<xsl:for-each select="//A">
<xsl:sort select="-count(ancestor::A)" data-type="number" />
<xsl:if test="position()=1">
<xsl:value-of select="count(ancestor-or-self::A)"/>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

which gives 4 on the originally posted example.

David
Jul 20 '05 #9
William Park wrote:
You had XSL and xmlgawk solution. Here is Bash shell solution:

start () { # Usage: start tag att=value ...
count=`echo ${XML_ELEMENT_STACK[*]|/$1} | wc -w`
[[ count -gt $1 ]] && eval $1=`echo $count`
}
xml -s start "<ROOT>...</ROOT>"
declare -p A B C
Very short indeed. But a bit cryptic.
Explanation:
- ${...|/glob} returns all array element matching 'glob' pattern.
In this case, 'A', 'B', 'C'.
This is a very powerful feature that is missing in xmlgawk.
In xmlgawk an explicite loop is needed.
- `echo $count` is needed to strip leading whitespaces put there by
'wc -w'.


The descendents of the Bourne shell are not really first choice
for arithmetic applications.
Jul 20 '05 #10
J?rgen Kahrs <Ju*********************@vr-web.de> wrote:
William Park wrote:
You had XSL and xmlgawk solution. Here is Bash shell solution:

start () { # Usage: start tag att=value ...
count=`echo ${XML_ELEMENT_STACK[*]|/$1} | wc -w`
[[ count -gt $1 ]] && eval $1=`echo $count`
}
xml -s start "<ROOT>...</ROOT>"
declare -p A B C
Very short indeed. But a bit cryptic.
Explanation:
- ${...|/glob} returns all array element matching 'glob' pattern.
In this case, 'A', 'B', 'C'.


This is a very powerful feature that is missing in xmlgawk.
In xmlgawk an explicite loop is needed.


This is only available in my patch Bash shell. Standard Bash/Ksh/Zsh
doesn't have it. In Python, it's called list comprehension. But, in
shell-speak, it's nothing more than parameter expansion (around for 30
years) plus some content filtering (denoted by '|').
- `echo $count` is needed to strip leading whitespaces put there
by 'wc -w'.


The descendents of the Bourne shell are not really first choice
for arithmetic applications.


Actually, integer expression is fairly complete. For example,
${var[i]}
${var:i:j}
(( i ))
both 'i' and 'j' can be full arithmetic expression. It's the float
point which is the problem. Bash can't do floating point. Awk is much
better at that.

--
William Park <op**********@yahoo.ca>
Open Geometry Consulting, Toronto, Canada
Jul 20 '05 #11

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
by: JP SIngh | last post by:
Hi There I am creating a search page and need help writing the code to build the sql string. I have 3 fields on the main page which a user can choose to enter search terms in any of the 3...
11
by: Petre Huile | last post by:
I have designed a site for a client, but they have hired an internet marketing person to incrase their search engine ranking and traffic. He wants to put extra-large fonts on every page which will...
2
by: Zambo via SQLMonster.com | last post by:
Hi! We have Sql Server 2000 in our server (NT 4). Our database have now about +350.000 rows with information of images. Table have lot of columns including information about image name, keywords,...
83
by: D. Dante Lorenso | last post by:
Trying to use the 'search' in the docs section of PostgreSQL.org is extremely SLOW. Considering this is a website for a database and databases are supposed to be good for indexing content, I'd...
38
by: Alan | last post by:
I want to change a 3 digits integer to characters, how can i do that? the 3 digits integer maybe 123, 23 or 3 I want to change the integer to "123", " 23" or " 3" thx
4
by: Tarique Jawed | last post by:
Alright I needed some help regarding a removal of a binary search tree. Yes its for a class, and yes I have tried working on it on my own, so no patronizing please. I have most of the code working,...
8
by: ignatova | last post by:
Hello, I have been using IBM Net Search Extender to perform full text searches on text columns in relational tables in DB2 without any problems until now. However it doesn't seam to function...
5
by: samoore33 | last post by:
I use the code below to return rows matching the state in the theState variable. I want to know if it is possible to search through the DataRow that I am returning with the search. I understand...
0
by: passion | last post by:
"Specialized Search Engines" along with Google Search Capability (2 in 1): http://specialized-search-engines.blogspot.com/ Billions of websites are available on the web and plenty of extremely...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.