using XSLT 2.0 to get an attribute value from nearest ancestor, of a specific element name, and adding to current node

Given this simplified input data:

<data>
	<section type="AAA">
	  <section type="CCC">..</section>
	  <section type="CCC">..</section>
	  <section type="CCC">..</section>
	</section>
	<section type="AAA">
	  <section type="CCC">..</section>
	  <section type="CCC">..</section>
	  <section type="CCC">..</section>
	</section>
	<section type="AAA">
		<section type="BBB">
		  <section type="CCC">..</section>
	  	  <section type="CCC">..</section>
	  	  <section type="CCC">..</section>
	  </section>	
	</section>
  <section type="CCC">..</section>
 	<section type="CCC">..</section>
 	<section type="CCC">..</section>
	<section type="BBB">
	  <section type="CCC">..</section>
  	  <section type="CCC">..</section>
  	  <section type="CCC">..</section>
  </section>	
</data>

Open in new window


For each section element in the file I want to add an attribute (prevType) that is populated with the type attribute of the section element that precedes it - it does not matter about the hierarchy of the section elements, I always want the previous one.
My sample data only shows the section elements but there will be a lot data in between the sections in the 'real' file.

<data>
	<section type="AAA">
	  <section type="CCC" prevType="AAA">..</section>
	  <section type="CCC" prevType="CCC">..</section>
	  <section type="CCC" prevType="CCC">..</section>
	</section>
	<section type="AAA" prevtype="CCC">
	  <section type="CCC" prevType="AAA">..</section>
	  <section type="CCC" prevType="CCC">..</section>
	  <section type="CCC" prevType="CCC">..</section>
	</section>
	<section type="AAA" prevType="CCC">
		<section type="BBB" prevType="AAA">
		  <section type="CCC" prevType="BBB">..</section>
	  	<section type="CCC" prevType="CCC">..</section>
	  	<section type="CCC" prevType="CCC">..</section>
	  </section>	
	</section>
  <section type="CCC" prevType="CCC">..</section>
 	<section type="CCC" prevType="CCC">..</section>
 	<section type="CCC" prevType="CCC">..</section>
	<section type="BBB" prevType="CCC">
	  <section type="CCC" prevType="BBB">..</section>
  	<section type="CCC" prevType="CCC">..</section>
  	<section type="CCC" prevType="CCC">..</section>
  </section>	
</data>

Open in new window



I think I need to examine and get what I need from the ancestor axis but am not sure how to put that into an XSLT command. Can anyone assist please?
LVL 1
LetterpartAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Geert BormansInformation ArchitectCommented:
preceding-sibling will only give you the section on the same level
preceding will give you the last section that closed

using preceding:: will give
<section type="AAA">
        <section type="CCC" prevType="AAA">..</section>
        <section type="CCC" prevType="CCC">..</section>
        <section type="CCC" prevType="CCC">..</section>
      </section>
      <section type="AAA" prevtype="AAA">
the bolded needs to be CCC

so I think you need some logic for the last element in document order that opened before the current one.
That is a trickier beast

Can you confirm that is what you need?
0
LetterpartAuthor Commented:
Yes, you're correct Geert - it's the trickier one that I need.
0
Geert BormansInformation ArchitectCommented:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">
    
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>
    
    <xsl:template match="node()">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates select="node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="section">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:choose>
                <xsl:when test="preceding-sibling::section">
                    <xsl:attribute name="prevType">
                        <xsl:value-of select="preceding-sibling::section[1]/descendant-or-self::section[last()]/@type"/>
                    </xsl:attribute>
                </xsl:when>
                <xsl:when test="parent::section">
                    <xsl:attribute name="prevType">
                        <xsl:value-of select="parent::section/@type"/>
                    </xsl:attribute>
                </xsl:when>
            </xsl:choose>
            <xsl:apply-templates select="node()"/>
        </xsl:copy>
    </xsl:template>
    
</xsl:stylesheet>

Open in new window


I hope this one is not too slow
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
LetterpartAuthor Commented:
That's great - working fine - thanks very much Geert.
0
Geert BormansInformation ArchitectCommented:
welcome, fun challenge actually
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
XML

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.