Solved

XSLT ----> preceding-sibling::

Posted on 2003-12-02
7
3,034 Views
Last Modified: 2013-11-18
Hello all,
            I am new to XSLT. I have a problem at hand where I have to insert a horizontal rule after a set of similar elements(all similar elements are already in sequential order). I was successful in doing it with the following code

                    <xsl:if test="((preceding-sibling::Insertion/Publication)[last()])">
                        <xsl:if test="not(Publication=((preceding-sibling::Insertion/Publication)[last()]))">
                            <tr>
                                <td colspan="20"><hr/></td>                                        
                            </tr>
                        </xsl:if>
                    </xsl:if>

PROBLEM: Though this works perfectly, whenever the XML file is huge, this code takes a considerable amount of time. I would be very grateful if anyone lead me to a better solution.

NOTE: The solution has to work fast on large XML file.

thanks,
Naveen.
0
Comment
Question by:naveen_damerla
  • 3
  • 2
  • 2
7 Comments
 
LVL 15

Expert Comment

by:dualsoul
ID: 9861390
hm...i don't understand well what do you want....
but why not to try get all Insertion/Publication one by one? like this:

<xsl:for-each select="Insertion/Publication">
          ...do something here with Publications if you want..........
</xsl:for-each>
<!-- insert horizonatal rule after all elements -->
<tr>
     <td colspan="20"><hr/></td>                                        
</tr>
........... continue processing....................

or didn't get what you want? if so please post more your xslt code, xml source and what do you want to get as output.
0
 

Author Comment

by:naveen_damerla
ID: 9861490
Maybe I wasnt clear enough
                                          Here I go, My XML looks like

           <Insertion>
            <RevisionType></RevisionType>
            <City>Ventura</City>
            <State>CA</State>
            <Publication>Ventura County Star</Publication>
              .
              . //more elements here
            </Insertion>

            <Insertion>
            <RevisionType></RevisionType>
            <City>Ventura</City>
            <State>CA</State>
            <Publication>Anothet County Star</Publication>
             .
             .//more elements here
            </Insertion>

XSLT IS:

     <xsl:if test="((preceding-sibling::Insertion/Publication)[last()])">
                     <xsl:if test="not(Publication=((preceding-sibling::Insertion/Publication)[last()]))">
                            <tr>
                                <td colspan="20"><hr/></td>                                        
                            </tr>
                        </xsl:if>
                    </xsl:if>

What I is want is a horizontal rule """" if """" the publication name is the not the same....and do nothing if it is the same.

That being said my XML files are xtremely huge, so......though the my XSLT works pefectly.....I would like to have a faster alternative.

thanks,
Naveen.
0
 
LVL 26

Accepted Solution

by:
rdcpro earned 500 total points
ID: 9861501
Use an XSLT key, and index all the nodes by the aspect you use to determine similarity.  Then you simply have to test if the current node is a new unique node, and insert the horizontal rule:

Using this XML:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="muenchrule.xslt"?>
<insertion>
    <publication>Foo</publication>
    <publication>Foo</publication>
    <publication>Foo</publication>
    <publication>Foo</publication>
    <publication>Foo</publication>
    <publication>Foo</publication>
    <publication>Foo</publication>
    <publication>Bar</publication>
    <publication>Bar</publication>
    <publication>Bar</publication>
    <publication>Bar</publication>
    <publication>Bar</publication>
    <publication>Bar</publication>
    <publication>Bar</publication>
    <publication>Bar</publication>
    <publication>Bar</publication>
    <publication>Snafu</publication>
    <publication>Snafu</publication>
    <publication>Snafu</publication>
    <publication>Snafu</publication>
    <publication>Snafu</publication>
    <publication>Snafu</publication>
</insertion>

And this XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:key name="kRule" match="publication" use="."/>
    <xsl:template match="insertion">
        <Table>
            <xsl:apply-templates select="publication"/>
        </Table>
    </xsl:template>
    <xsl:template match="publication">
        <xsl:if test="generate-id() = generate-id(key('kRule', .)) and position() !=1">
            <tr>
                <td colspan="20"><hr/></td>
            </tr>
        </xsl:if>
            <tr>
                <td colspan="20"><xsl:value-of select="."/></td>
            </tr>
    </xsl:template>
</xsl:stylesheet>

You get a horizontal rule between each unique group, but not before the first one.  This should work fairly quickly for even large sets of nodes.

Regards,
Mike Sharp
0
DevOps Toolchain Recommendations

Read this Gartner Research Note and discover how your IT organization can automate and optimize DevOps processes using a toolchain architecture.

 
LVL 15

Expert Comment

by:dualsoul
ID: 9861611
>That being said my XML files are xtremely huge, so......though the my XSLT works pefectly.....I would like to have a faster alternative.

may be Mike's suggestion helps you, i think.
 but if you have trouble with perfomance, you should know XSLT is not scalable solution...so if you think your xml files can enlarge in future may be you should think about another architecture...XQuery for instance
0
 

Author Comment

by:naveen_damerla
ID: 9862139
Thank you rdcpro,
 
Your answer sounds really promising(havent tried it)....but I am a completely new to XSLT, this being my 2nd day.......AT the risk of sounding dumb, I would like to ask one more thing....
         If there is already a <xsl:for-each select="Insertions/Insertion">
in the XSLT, how would the answer change

plz note: there will be 500+ elements in the insertions node.


XML looks like:
------------------
<insertions>
        <Insertion>
            <RevisionType></RevisionType>
            <City>Ventura</City>
            <State>CA</State>
            <Publication>Ventura County Star</Publication>
              .
              . //more elements here
            </Insertion>

            <Insertion>
            <RevisionType></RevisionType>
            <City>Ventura</City>
            <State>CA</State>
            <Publication>Anothet County Star</Publication>
             .
             .//more elements here
            </Insertion>

             //500 more insertion elements
 </insertions>

XSLT like:
---------------
<xsl:for-each select="Insertions/Insertion">
                    <xsl:if test="((preceding-sibling::Insertion/Publication)[last()])">
                    <xsl:if test="not(Publication=((preceding-sibling::Insertion/Publication)[last()]))">
                            <!-- inserting horizontal rule-->
                            <tr>
                                <td colspan="20"><hr/></td>                                        
                            </tr>
                        </xsl:if>
                    </xsl:if>
                <tr>
                 <!-- REST OF MY CODE HERE-->
                </tr>


please advise,
thank you rdcpro
Naveen.
0
 
LVL 26

Assisted Solution

by:rdcpro
rdcpro earned 500 total points
ID: 9863180
Well, in that case only the path for the use attribute, and the path to the key() change:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:key name="kRule" match="insertion" use="publication"/>
    <xsl:template match="insertions">
    Number of Insertions:  <xsl:value-of select="count(insertion)"/>
        <Table>
            <xsl:for-each select="insertion">
                <xsl:if test="generate-id() = generate-id(key('kRule', publication)) and position() !=1">
                    <tr>
                        <td colspan="20"><hr/></td>
                    </tr>
                </xsl:if>
                    <tr>
                        <td colspan="20"><xsl:value-of select="publication"/></td>
                    </tr>
                   
            </xsl:for-each>
       </Table>
    </xsl:template>
</xsl:stylesheet>

Note that my XML is not the same case as yours...that is, insertion not Insertion...so watch out.

But with 822 <inserton> elements, it transforms nearly instantly on my desktop.  Parsing the XML is probably going to be a major portion of the overhead, and if you use FreeThreadDomDocument, and caching, you might be surprised how well it scales, assuming efficient XSLT.

This technique is Muenchian grouping, and I have examples and a tutorial on my site:
Code example:
http://dev.rdcpro.com/Members/rdcpro/snippets/columnrowgrouping/
tutorial:
http://dev.rdcpro.com/zones/xml/xslt/faqroot/faq-grouping-1.1

Caching techniques for ASP:
http://dev.rdcpro.com/Members/rdcpro/snippets/cachingtemplates/


Regards,
Mike Sharp
0
 

Author Comment

by:naveen_damerla
ID: 9884127
Thank u rdcpro. I just plugged in the partial code at the right place and PRESTO!!.....evrything works.....and 43 pages of PDF generation was under 2 minutes.

thanks again.....
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

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

Suggested Solutions

SASS allows you to treat your CSS code in a more OOP way. Let's have a look on how you can structure your code in order for it to be easily maintained and reused.
Have you tried to learn about Unicode, UTF-8, and multibyte text encoding and all the articles are just too "academic" or too technical? This article aims to make the whole topic easy for just about anyone to understand.
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…
Viewers will learn one way to get user input in Java. Introduce the Scanner object: Declare the variable that stores the user input: An example prompting the user for input: Methods you need to invoke in order to properly get  user input:

861 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

Need Help in Real-Time?

Connect with top rated Experts

23 Experts available now in Live!

Get 1:1 Help Now