Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

Counting ancestors using XSLT for storage in a variable

Posted on 2009-06-28
3
Medium Priority
?
514 Views
Last Modified: 2013-11-18
Hi. This is my first post. English is not my first language, and I am fairly new to xsl as well to make matters worse. Hope I can make myself understood despite this handicap.

I have been assigned the task to transform an xml document to html using an xsl style sheet. The xml file is a very special "animal". It is originally sgml but the file is to be translated using a translation tool, and for this purpose the file content has been wrapped in xml tags and saved as xml. The object of the transformation to html is to allow the translator to preview the translated document in a way that mimics the original document layout with paragraph numbering, indentation, fonts and font sizes etc.

The xml structure can be regarded as flat, all of the tags that I am interested in are on the same level. The name of the original sgml tag is stored in an attribute called DisplayText. By looking at the Type attribute it is possible to determine if it is the opening or closing sgml tag, i.e. <paragraph> or </paragraph>, for example:

<ut Type="start" DisplayText="paragraph">&lt;paragraph&gt;></ut>
Some content that should be translated
<ut Type="end" DisplayText="paragraph">&lt;/paragraph&gt;</ut>

The structure of the sgml document is more complex with headers and subitems. It contains lists where the list items are numbered from 1 and up, or A, B, C or roman numericals. And a list could be a sublist to another list. A simple sample would look like this:

<list>
      <listitem>Item 1</listitem>
      <listitem>Item 2</listitem>
      <listitem>Item 3</listitem>
      <list>
            <listitem>Item A</listitem>
            <listitem>Item B</listitem>
      </list>
</list>

And the document saved as xml for translation tool:

<ut Type="start"  DisplayText="list">&lt;list&gt;</ut>
<ut Type="start"  DisplayText="listitem">&lt;listitem&gt;</ut>
Item 1
<ut Type="end"  DisplayText="listitem">&lt;/listitem&gt;</ut>
<ut Type="start"  DisplayText="listitem">&lt;listitem&gt;</ut>
Item 2
<ut Type="end"  DisplayText="listitem">&lt;/listitem&gt;</ut>
<ut Type="start"  DisplayText="listitem">&lt;listitem&gt;</ut>
Item 3
<ut Type="end"  DisplayText="listitem">&lt;/listitem&gt;</ut>
<ut Type="start"  DisplayText="list">&lt;list&gt;</ut>
<ut Type="start"  DisplayText="listitem">&lt;listitem&gt;</ut>
Item A
<ut Type="end"  DisplayText="listitem">&lt;/listitem&gt;</ut>
<ut Type="start"  DisplayText="listitem">&lt;listitem&gt;</ut>
Item B
<ut Type="end"  DisplayText="listitem">&lt;/listitem&gt;</ut>
<ut Type="end"  DisplayText="list">&lt;/list&gt;</ut>
<ut Type="end"  DisplayText="list">&lt;/list&gt;</ut>

Lets say that a matched ut element describes a <listitem> tag:

<ut Type="start" DisplayText="listitem">&lt;listitem&gt;></ut>

then I must find out to which list it belongs, so that I can indent the entry properly. One idea would be to count <ut> elements that describe an opening <list> tag:

<ut Type="start"  DisplayText="list">&lt;list&gt;</ut>

and then count closing </list> tags:

<ut Type="end"  DisplayText="list">&lt;/list&gt;</ut>

 If there is one more opening tag than closing tag the item would belong to a top level list. If there are two opening tags more than closing tags the item belong to a list inside of a list and so on.

Is it possible to count ancestors of a specific type, where the information we need is stored in an attribute, and put the value in a variable? I.e. count all <ut> elements above the current where the attribute DisplayText = list and the Type = start and then where Type = end?

Does this approach make any sense at all or would you more experienced in xslt choose a different solution? Is it possible for example, using xslt, to rebuild the original document structure (using the sgml tag information from the DisplayText and Type attributes) in some way and then apply a style sheet to this document?
0
Comment
Question by:BjornEM
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 2
3 Comments
 
LVL 13

Expert Comment

by:numberkruncher
ID: 24733146
> Is it possible to count ancestors of a specific type, where the information we need is
> stored in an attribute, and put the value in a variable?

You can count the ancestors of a specific type using the XPath expression:

count(ancestor-or-self::list)

To place this in the attribute of your output you would simply use the XSLT:


   .... OTHER XSLT ....



> I.e. count all  elements above the current where the attribute DisplayText = list and the
> Type = start and then where Type = end?

(SEE BELOW FOR SOURCE)

Are you trying to transform SOURCE #1 into SOURCE #2? If so, then SOURCE #3 should do the trick.


> Does this approach make any sense at all or would you more experienced in xslt choose a
> different solution?

I do not fully understand your problem. Why are you transforming into  nodes?


> Is it possible for example, using xslt, to rebuild the original document structure (using the sgml tag
> information from the DisplayText and Type attributes) in some way and then apply a style sheet to
> this document?

If you are trying to convert your SGML into HTML, then yes, you can match the same document structure as the input where elements and attributes are transformed into HTML equivalents.

You can use the extremely powerful XSLT element named  to achieve automatic section, chapter, figure, table, etc. numbering.
SOURCE #1
=========
 
<list>
      <listitem>Item 1</listitem>
      <listitem>Item 2</listitem>
      <listitem>Item 3</listitem>
      <list>
            <listitem>Item A</listitem>
            <listitem>Item B</listitem>
      </list>
</list>
 
 
SOURCE #2
=========
 
<ut Type="start"  DisplayText="list">&lt;list&gt;</ut> 
<ut Type="start"  DisplayText="listitem">&lt;listitem&gt;</ut> 
Item 1 
<ut Type="end"  DisplayText="listitem">&lt;/listitem&gt;</ut> 
<ut Type="start"  DisplayText="listitem">&lt;listitem&gt;</ut> 
Item 2 
<ut Type="end"  DisplayText="listitem">&lt;/listitem&gt;</ut> 
<ut Type="start"  DisplayText="listitem">&lt;listitem&gt;</ut> 
Item 3 
<ut Type="end"  DisplayText="listitem">&lt;/listitem&gt;</ut> 
<ut Type="start"  DisplayText="list">&lt;list&gt;</ut> 
<ut Type="start"  DisplayText="listitem">&lt;listitem&gt;</ut> 
Item A 
<ut Type="end"  DisplayText="listitem">&lt;/listitem&gt;</ut> 
<ut Type="start"  DisplayText="listitem">&lt;listitem&gt;</ut> 
Item B 
<ut Type="end"  DisplayText="listitem">&lt;/listitem&gt;</ut> 
<ut Type="end"  DisplayText="list">&lt;/list&gt;</ut> 
<ut Type="end"  DisplayText="list">&lt;/list&gt;</ut> 
 
 
SOURCE #3 : THE TRANSFORM
=========================
 
<xsl:template match="list">
	<ut Type="start" DisplayText="list" Depth="{count(ancestor-or-self::list)}">&lt;list&gt;</ut>
	<xsl:apply-templates select="listitem"/>
	<ut Type="end" DisplayText="list" Depth="{count(ancestor-or-self::list)}">&lt;/list&gt;</ut>
</xsl:template>
 
<xsl:template match="list/listitem">
	<ut Type="start" DisplayText="list" Depth="{count(ancestor::list)}">&lt;listitem&gt;</ut>
	<xsl:value-of select="."/>
	<ut Type="end" DisplayText="list" Depth="{count(ancestor::list)}">&lt;/listitem&gt;</ut>
</xsl:template>

Open in new window

0
 
LVL 13

Accepted Solution

by:
numberkruncher earned 2000 total points
ID: 24733196
For list items you could use the specialized HTML list elements OL and LI. Numbering is automatic with those.

Or, you could use something like the following, and hard-code the numbering into the list items. This approach also deals with chapter numbering (see below).
INPUT SGML (DIFFERENT TO YOURS):
================================
<document>
    <title>My Document Title</title>
    <chapter>
        <heading>My Chapter</heading>
        <para>Here is a list...</para>
        <list>
            <listitem>Item 1</listitem>
            <listitem>Item 2</listitem>
            <listitem>Item 3</listitem>
            <list>
                <listitem>Item A</listitem>
                <listitem>Item B</listitem>
            </list>
        </list>
    </chapter>
</document>
 
 
OUTPUT HTML:
============
<html> 
   <head> 
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 
      <title>My Document Title</title><style type="text/css"> 
                    .list { margin-left: 15pt; }
                    .listitem { margin-left: 15pt; }
                </style></head> 
   <body> 
      <div class="toc"> 
         <h3>Table of Contents</h3> 
         <div>1. My Chapter</div> 
      </div> 
      <div class="content-body"> 
         <h2>1. My Chapter</h2> 
         My Chapter
         
         <p>Here is a list...</p> 
         
         <div class="list"> 
            <div class="listitem">I. Item 1</div> 
            <div class="listitem">II. Item 2</div> 
            <div class="listitem">III. Item 3</div> 
            <div class="list">IV. 
               <div class="listitem">I. Item A</div> 
               <div class="listitem">II. Item B</div> 
            </div> 
         </div> 
         
      </div> 
   </body> 
</html>
 
 
XSL TRANSFORM:
==============
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
 
    <xsl:template match="document">
        <html>
            <head>
                <title>
                    <xsl:value-of select="title"/>
                </title>
                <style type="text/css">
                    .list { margin-left: 15pt; }
                    .listitem { margin-left: 15pt; }
                </style>
            </head>
            <body>
                <div class="toc">
                    <h3>Table of Contents</h3>
                    <xsl:apply-templates select="chapter" mode="toc"/>
                </div>
                <div class="content-body">
                    <xsl:apply-templates select="chapter"/>
                </div>
            </body>
        </html>
    </xsl:template>
 
 
    <!-- TOC -->
    <xsl:template match="chapter" mode="toc">
        <div>
            <xsl:number level="single" count="chapter"/>
            <xsl:text>. </xsl:text>
            <xsl:value-of select="heading"/>
        </div>
    </xsl:template>
 
 
    <!-- CONTENT BODY -->
    <xsl:template match="chapter">
        <h2>
            <xsl:number level="single" count="chapter"/>
            <xsl:text>. </xsl:text>
            <xsl:value-of select="heading"/>
        </h2>
        <xsl:apply-templates/>
    </xsl:template>
    
    
    <xsl:template match="para">
        <p>
            <xsl:value-of select="."/>
        </p>
    </xsl:template>
    
 
    <xsl:template match="list">
        <div class="list">
            <xsl:apply-templates select="list | listitem" mode="list"/>
        </div>
    </xsl:template>
    
    <xsl:template match="list" mode="list">
        <div class="list">
            <xsl:number level="single" count="listitem | list" format="I"/>
            <xsl:text>. </xsl:text>
            <xsl:apply-templates select="list | listitem" mode="list"/>
        </div>
    </xsl:template>
    
    <xsl:template match="listitem" mode="list">
        <div class="listitem">
            <xsl:number level="single" count="listitem | list" format="I"/>
            <xsl:text>. </xsl:text>
            <xsl:value-of select="."/>
        </div>
    </xsl:template>
 
</xsl:stylesheet>

Open in new window

0
 

Author Closing Comment

by:BjornEM
ID: 31597738
Thank you for your suggested solution, it helped me a lot.
0

Featured Post

AWS Certified Solutions Architect - Associate

This course has been developed to provide you with the requisite knowledge to not only pass the AWS CSA certification exam but also gain the hands-on experience required to become a qualified AWS Solutions architect working in a real-world environment.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Preface This is the third article about the EE Collaborative Login Project. A Better Website Login System (http://www.experts-exchange.com/A_2902.html) introduces the Login System and shows how to implement a login page. The EE Collaborative Logi…
Introduction Knockoutjs (Knockout) is a JavaScript framework (Model View ViewModel or MVVM framework).   The main ideology behind Knockout is to control from JavaScript how a page looks whilst creating an engaging user experience in the least …
Viewers will learn about arithmetic and Boolean expressions in Java and the logical operators used to create Boolean expressions. We will cover the symbols used for arithmetic expressions and define each logical operator and how to use them in Boole…
The viewer will learn how to create and use a small PHP class to apply a watermark to an image. This video shows the viewer the setup for the PHP watermark as well as important coding language. Continue to Part 2 to learn the core code used in creat…

688 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question