0

I've inherited an XQuery app running in eXist-db and I've been able to learn enough XQuery to tidy it up a bit, but I'm struggling with the final change I need to do.

The app has an HTML file stored in a collection in the following format:

<html>
    <head>...</head>
    <body>
        <div class="part">
            <div class="chapter">
                <div class="section">
                    <p>Text 1</p>
                    <p>Text 2</p>
                    <p>Text 3</p>
                </div>
                <div class="section">
                    <p>Text 4</p>
                    <p>Text 5</p>
                    <p>Text 6</p>
                </div>
            </div>
        </div>
        ...
        <div class="part">
            <div class="chapter">
                <div class="section">
                    <p>Text 1</p>
                    <p>Text 2</p>
                    <p>Text 3</p>
                </div>
                <div class="section">
                    <p>Text 1</p>
                    <p>Text 2</p>
                    <p>Text 3</p>
                </div>
            </div>
        </div>
        ...
    </body>
</html>

The <body> has multiple "part"s, with each "part" having multiple "chapter"s which themselves can have multiple "section"s etc.

I'm trying to do a search feature, and I've got the following code which works, but not as I need it to:

declare function app:search-result($node as node(), $model as map(*), $q as xs:string) {
    let $content := doc("/db/apps/EI/resources/publications/EI.html"))
    for $hit in $content//p[ft:query(., concat("'", $q, "'"))] 
        order by ft:score($hit) descending
        return
            $hit
};

At the moment the function only returns the pure text within the <p> it was found, but what I need is to find out every part, chapter and section DIVs it was found in

e.g., if I search for "text 1" I need to know it was found in:

1st part, 1st chapter, 1st section

2nd part, 1st chapter, 1st section

2nd part, 1st chapter, 2nd section

etc

This is where I'm stumped. Any ideas?

Jordan Wall
  • 95
  • 1
  • 2
  • 9

1 Answers1

4

Use the parent or ancestor axes to "climb down the tree" again. If you're at a text node, and want the parent node (containing the text node), use $hit/parent::*. If you want to find the matching chapter, go for $hit/ancestor::div[@class="chapter"] (and similarly for the other elements).

For the case that you have nested chapters, add the positional predicate [1] to find the most specific ancestor.

Be aware that the class attribute might contain multiple classes, and needs special handling when matching it!

Community
  • 1
  • 1
Jens Erat
  • 37,523
  • 16
  • 80
  • 96