XPath - How to query for <dd> elements ?

A

Andy Dingley

Imagine the XHTML "definition list" structure

<dl>
<dt>A</dt>
<dd>a</dd>

<dt>B</dt>
<dd>b1</dd>
<dd>b2</dd>

<dt>C</dt>

<dt>D</dt>
[ ...]
</dl>


Given the element containing "A" as the context node, how can I retrieve
the elements for "a", similarly "B" for "b1,b2" etc. ?

Using ./preceding-sibling::* [1] [self::dd]
I can retrieve the elements for "A" ("a") and "C" (an empty set)
However I can't see any way to get "b1" & "b2", just the first "b1"


Thanks for any advice
 
J

Joseph Kesselman

The simple-but-ugly way is to explicitly scan through the following
siblings until you hit the next <dt> or run out, using a recursive named
template.

Personally, I'd try to convince whoever was authoring the input document
to abandon the HTML markup on input (even if that's what you generate on
output) and use something with more structure to it, such as:

<deflist>
<entry><term>...</term><def>....</def><def>....</def></entry>
</deflist>

Then it's trivial; the definitions are the <def> children of the
<term>'s parent.
 
G

George Bina

Use
following-sibling::dd[preceding-sibling::dt[1]=current()]
get the following dd element whose first preceding dt is the surrent dt
element.


For instance the folllowing stylesheet
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:eek:utput indent="yes"/>
<xsl:template match="/">
<result>
<xsl:apply-templates select="//dt"/>
</result>
</xsl:template>

<xsl:template match="dt">
<for value="{.}">
<xsl:for-each

select="following-sibling::dd[preceding-sibling::dt[1]=current()]">
<got value="{.}"/>
</xsl:for-each>
</for>
</xsl:template>
</xsl:stylesheet>

will give you

<?xml version="1.0" encoding="utf-8"?>
<result>
<for value="A">
<got value="a"/>
</for>
<for value="B">
<got value="b1"/>
<got value="b2"/>
</for>
<for value="C"/>
<for value="D"/>
</result>

Note that the above assumes no namespace for the source elements, if
you use the XHTML namespace then you need to qualify the name tests
with the appropriate prefix, that is instead of dd for instance you
should have xhtml:dd and declare the XHTML namespace mapped to xhtml
prefix.

Best Regards,
George
 
J

Joe Kesselman

George said:
following-sibling::dd[preceding-sibling::dt[1]=current()]
get the following dd element whose first preceding dt is the current dt
element.

.... Yep, that should work, and it's certainly more compact.

Performance of this vs. other solutions is going to depend on the exact
characteristics of your XSLT processor, and so is hard to predict
reliably. I'm not sure whether the one I've been using would recognize
the optimization opportunities in that expression or not; I should check.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,001
Messages
2,570,255
Members
46,853
Latest member
GeorgiaSta

Latest Threads

Top