• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 3105
  • Last Modified:

XSLT ----> preceding-sibling::

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
naveen_damerla
Asked:
naveen_damerla
  • 3
  • 2
  • 2
2 Solutions
 
dualsoulCommented:
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
 
naveen_damerlaAuthor Commented:
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
 
rdcproCommented:
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
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
dualsoulCommented:
>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
 
naveen_damerlaAuthor Commented:
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
 
rdcproCommented:
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
 
naveen_damerlaAuthor Commented:
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

New feature and membership benefit!

New feature! Upgrade and increase expert visibility of your issues with Priority Questions.

  • 3
  • 2
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now