CurryInfo: xml-3.0.0 / XCuery

classes:

              
documentation:
------------------------------------------------------------------------------
--- Library for declarative processing XML data.
--- 
--- This libary contains definitions of combinators which can be used
--- to specify queries and transformations on XML data in a high-level
--- declarative manner. Actually, these combinators can be used as
--- functional patterns in operations to query and transform XML data.
---
--- The ideas and usage of this library is described in the paper
---
--- > M. Hanus: Declarative Processing of Semistructured Web Data.
--- > Technical Communications of the 27th International Conference
--- > on Logic Programming (ICLP 2011),
--- > Leibniz International Proceedings in Informatics (LIPIcs),
--- > Vol. 11, pp. 198-208, 2011
--- > [Online](https://doi.org/10.4230/LIPIcs.ICLP.2011.198)
---
--- @author Michael Hanus
--- @version February 2025
------------------------------------------------------------------------------
name:
XCuery
operations:
anyorder deepXElem deepXml deepXml' noTagOf optXml with withOthers xml'
sourcecode:
{-# OPTIONS_FRONTEND -Wno-overlapping #-}

module XCuery where

import XML

------------------------------------------------------------------------------

--- The operation `with` evaluates to all lists containing the
--- elements in the argument in the same order. For instance,
---
---     > with [1,2]
---     1:2:_a
---     1:_a:2:_b
---     1:_a:_b:2:_c
---     ...
---
--- This operation can be used in a pattern to match XML structures
--- having at least the given elements as children, as in
---
---     getNamePhone
---       (xml "entry"
---            (with [xml "name"  [xtxt name],
---                   xml "phone" [xtxt phone]])) = name ++ ": " ++ phone
with :: Data a => [a] -> [a]
with []     = unknown
with (x:xs) = unknown ++ x : with xs

--- The operation `xml'` can be used to match an XML structure with a given
--- tag and children independent of the attributes. For instance,
---
---     getName (xml’ "entry" (with [xml’ "name" [xtxt n]])) = n
---
--- matches an XML element with tag `entry` and some child element with
--- tag `name`, independent of the possible attributes attached to these
--- elements.
xml' :: String -> [XmlExp] -> XmlExp
xml' t xs = XElem t unknown xs

--- The operation `anyorder` returns all permutations of the input list.
--- It can be used in a pattern to match XML structures with the given
--- elements in arbitrary order, as in
---
---     getNamePhone
---       (xml "entry"
---         (with (anyorder [xml "name"  [xtxt name],
---                          xml "phone" [xtxt phone]]))) = name ++ ": " ++ phone
anyorder :: [a] -> [a]
anyorder []     = []
anyorder (x:xs) = insert (anyorder xs)
 where insert []     = [x]
       insert (y:ys) = x:y:ys  ?  y : insert ys


--- The operation `deepXml` evaluates to any XML structure containing
--- an XML structure with the given tag and children at an abritrarily
--- deep position. For instance,
---
---     getNamePhone
---       (deepXml "entry"
---                (with [xml "name"  [xtxt name],
---                       xml "phone" [xtxt phone]])) = name ++ ": " ++ phone
---
--- allows to query an XML structure having a structure with tag `entry`
--- and children structures with tags `name` and `phone`.
deepXml :: String -> [XmlExp] -> XmlExp
deepXml tag elems = xml tag elems
deepXml tag elems = xml' unknown (unknown ++ [deepXml tag elems] ++ unknown)

--- This operation is similar to 'deepXml' but matches the XML structures
--- independent of their attributes.
deepXml' :: String -> [XmlExp] -> XmlExp
deepXml' tag elems = xml' tag elems
deepXml' tag elems = xml' unknown (unknown ++ [deepXml' tag elems] ++ unknown)

--- This operation is similar to 'deepXml' but allows to provide a list
--- of attributes to the matched XML structures.
--- For instance,
---
---     getMaleFirstNames
---       (deepXElem "first" (with [("sex","male")]) [xtxt f]) = f
---
--- matches an XML structure containing an XML structure with tag `first`
--- and some attribute `sex` with value `male`.
deepXElem :: String -> [(String,String)] -> [XmlExp] -> XmlExp
deepXElem tag attrs elems = XElem tag attrs elems
deepXElem tag attrs elems =
  xml' unknown (unknown ++ [deepXElem tag attrs elems] ++ unknown)

--- The predicate `noTagOf` returns `True` if the given tag is not a tag
--- of all argument XML structures.
noTagOf :: String -> [XmlExp] -> Bool
noTagOf tag = all ((/= tag) . tagOf)

--- The operation `withOthers` is similar to 'with' but has a second argument
--- that contains the child nodes that are present but not part of the
--- first argument. One can use this operation to denote the
--- `unmatched` part of an XML structure in order to put conditions on it.
--- For instance, if one wants to get the name and phone number of an entry
--- that has no email address, one can use the following definition:
--- 
---     getNamePhoneWithoutEmail
---       (deepXml "entry"
---          (withOthers [xml "name" [xtxt name], xml "phone" [xtxt phone]]
---                      others))
---       | "email" `noTagOf` others
---       = name ++ ": " ++ phone
withOthers :: Data a => [a] -> [a] -> [a]
withOthers ys zs = withAcc [] ys zs
 where -- Accumulate remaining elements:
   withAcc prevs [] others | others=:=prevs++suffix = suffix
                                             where suffix free
   withAcc prevs (x:xs) others =
      prefix ++ x : withAcc (prevs++prefix) xs others
                                             where prefix free

--- The operation `optXml` can be used in transformations of XML elements
--- to insert a structure with a given tag depending on the presence
--- of this tag in a list of XML strucutres.
--- For this purpose, `optXml t xs ys` evaluates to `xml t xs`
--- if there is no element with tag `t` in `ys`, otherwise the first element
--- of `ys` with tag `t` is returned.
--- 
--- The following definition shows a usage of `optXml`:
--- 
---     transNickPhone
---       (deepXml "entry"
---                (withOthers [xml "name"  [xtxt n],
---                             xml "first" [xtxt f],
---                             xml "phone" phone]
---                            others)) =
---       xml "nickphone" [optXml "nickname" [xtxt (f++n)] others,
---                        xml "phone" phone]
optXml :: String -> [XmlExp] -> [XmlExp] -> XmlExp
optXml tag elems [] = xml tag elems
optXml tag elems (x:xs) =
  if tag == tagOf x then x else optXml tag elems xs

------------------------------------------------------------------------------
types:

              
unsafe:
safe