Search code examples
xmlxqueryunorderedflwor

Determining if an order pattern in nodes is followed with XQuery


I have the xml code below with 4 <e> nodes, and I need to create a XQuery procedure to which I pass 2 parameters (even 3) param1=EP, param2=PRF and determined which nodes <e> present the nodes in that order EP before PRF. After that reprint the same structure but with the node must have a new attribute called ordered with the value yes or no <e ordered="yes">

<?xml version="1.0" encoding="UTF-8"?>
<results>
<e>
<element sign="none;isroot:yes">
    <e_afl>kamatsa</e_afl><e_asl>crawl</e_asl>
</element>
<element sign="equal">
    <e_afl>vai</e_afl><e_asl>DUR</e_asl>
</element>
<element sign="hyphen">
    <e_afl>t</e_afl><e_asl>EP</e_asl>
</element>
<element sign="hyphen">
    <e_afl>ak</e_afl><e_asl>PRF</e_asl>
</element>
<element sign="hyphen">
    <e_afl>i</e_afl><e_asl>REAL</e_asl>
</element>
<element sign="equal">
    <e_afl>na</e_afl><e_asl>1SG.O</e_asl>
</element>
</e>
<e>
<element sign="none">
    <e_afl>i</e_afl><e_asl>3m.A</e_asl>
</element>
<element sign="equal;isroot:yes">
    <e_afl>pos</e_afl><e_asl>hit</e_asl>
</element>
<element sign="hyphen">
    <e_afl>a</e_afl><e_asl>EP</e_asl>
</element>
<element sign="hyphen">
    <e_afl>vai</e_afl><e_asl>DUR</e_asl>
</element>
<element sign="hyphen">
    <e_afl>ve</e_afl><e_asl>FRUS</e_asl>
</element>
<element sign="hyphen">
    <e_afl>t</e_afl><e_asl>EP</e_asl>
</element>
<element sign="hyphen">
    <e_afl>ak</e_afl><e_asl>PRF</e_asl>
</element>
<element sign="hyphen">
    <e_afl>a</e_afl><e_asl>REAL</e_asl>
</element>
<element sign="equal">
    <e_afl>na</e_afl><e_asl>1SG.O</e_asl>
</element>
</e>
<e>
<element sign="none">
    <e_afl>y</e_afl><e_asl>3m.A</e_asl>
</element>
<element sign="equal;isroot:yes">
    <e_afl>aNt</e_afl><e_asl>work</e_asl>
</element>
<element sign="hyphen">
    <e_afl>vai</e_afl><e_asl>DUR</e_asl>
</element>
<element sign="hyphen">
    <e_afl>t</e_afl><e_asl>PRF</e_asl>
</element>
<element sign="hyphen">
    <e_afl>ak</e_afl><e_asl>CAUS.SOC</e_asl>
</element>
<element sign="hyphen">
    <e_afl>ak</e_afl><e_asl>EP</e_asl>
</element>
<element sign="hyphen">
    <e_afl>i</e_afl><e_asl>REAL</e_asl>
</element>
<element sign="equal">
    <e_afl>ri</e_afl><e_asl>3m.O</e_asl>
</element>
</e>
<e>
<element sign="none">
    <e_afl>n</e_afl><e_asl>1SG.S</e_asl>
</element>
<element sign="equal;isroot:yes">
    <e_afl>aNt</e_afl><e_asl>work</e_asl>
</element>
<element sign="hyphen">
    <e_afl>a</e_afl><e_asl>EP</e_asl>
</element>
<element sign="hyphen">
    <e_afl>vai</e_afl><e_asl>DUR</e_asl>
</element>
<element sign="hyphen">
    <e_afl>t</e_afl><e_asl>EP</e_asl>
</element>
<element sign="hyphen">
    <e_afl>ak</e_afl><e_asl>PRF</e_asl>
</element>
<element sign="hyphen">
    <e_afl>i</e_afl><e_asl>REAL</e_asl>
</element>
</e>
</results>

Solution

  • BaseX supports XQuery Update. It also has a nice (at the moment still implementation-specific, but an issue is currently pending at the W3C for standardization) operator called update, simplifying transform expressions.

    Please note that your XML is currently not well-formed as XML documents always have a single root element. Provided you add this, the following should work:

    for $e in doc("your-xml-file.xml")//e
    return
      if ($e/element[e_asl = "EP"][following-sibling::element/e_asl = "PRF"])
      then $e update insert node (attribute {"ordered"} {"yes"}) into .
      else $e
    

    By the way, if you want to modify your original database, you can issue the following command

    SET WRITEBACK true
    

    (or start BaseX using the command line and the -u command) and execute the following:

    for $e in doc("e.xml")//e[element[e_asl = "EP"][following-sibling::element/e_asl = "PRF"]]
    return insert node (attribute {"ordered"} {"yes"}) into $e