1
votes

Considering the following XML:

<?xml version="1.0" encoding="UTF-8"?>
<publication>
    <scientificPublication>
        <id>2347823476</id>
        <book>
            <chapter>
                <Title>ChapterTitle</Title>
                <sequenceNumber>0</sequenceNumber>
                <correctionNumber>0</correctionNumber>
            </chapter>
            <chapter>
                <Title>ChapterTitle</Title>
                <sequenceNumber>0</sequenceNumber>
                <correctionNumber>1</correctionNumber>
            </chapter>
            <chapter>
                <Title>ChapterTitle</Title>
                <sequenceNumber>0</sequenceNumber>
                <correctionNumber>2</correctionNumber>
            </chapter>
            <chapter>
                <Title>ChapterTitle</Title>
                <sequenceNumber>1</sequenceNumber>
                <correctionNumber>0</correctionNumber>
            </chapter>
            <chapter>
                <Title>ChapterTitle</Title>
                <sequenceNumber>1</sequenceNumber>
                <correctionNumber>1</correctionNumber>
            </chapter>
            <chapter>
                <Title>ChapterTitle</Title>
                <sequenceNumber>2</sequenceNumber>
                <correctionNumber>0</correctionNumber>
            </chapter>
        </book>
    </scientificPublication>
</publication>

What I need is to retrieve all the chapters with the same sequenceNumber, where correctionNumber is less than the max of correctionNumber.

So in the case of the example it would be the chapters with (sequenceNumber,correctionNumber): [(0,0),(0,1),(1,0)]

My idea was to create a function to return the MAX, considering this post, and use this as a base to create a clause to get all the chapters with correctionNumber less than the MAX. But I'm not sure how would I be able to iterate over the chapters, getting all the sequenceNumber, to create this clause.

It would be something like:

//chapter[(./*[((sequenceNumber='X')and(correctionNumber<'MAX'))or((sequenceNumber='Y')and(correctionNumber<'MAX'))or...])]
2

2 Answers

1
votes

Assuming your XML is sorted as your input example, you could try the following XPath 1.0 expression :

//sequenceNumber[.=preceding::sequenceNumber or .=following::sequenceNumber][following-sibling::correctionNumber[.<following::correctionNumber[1]]]/parent::chapter

We first select the duplicated sequenceNumber. Each one fulfill the following-condition : their correctionNumber sibling is inferior to the next and first following correctionNumber. We finally get the parent element of these sequenceNumber elements.

Output : 3 chapters (0,0;0,1;1,0)

0
votes

As a one-line XPath expression:

//chapter[sequenceNumber lt max(//sequenceNumber) and correctionNumber lt max(//correctionNumber)]

However, depending upon the processor you are using and the size of your documents, you may find that it does not perform as well as if you were to let variables with those max values and use the variables within the predicate filters:

let $max-sequence := max(//sequenceNumber)
let $max-correction := max(//correctionNumber)
return
  //chapter[sequenceNumber lt $max-sequence and correctionNumber lt $max-correction]