High-level interface

Module XMLCombinators provides a high-level XML programming interface. Like HaXML, it is based on gluing together Filters, where a Filter is a function from nodes to lists of nodes, or more generally from any type a to lists of any other type b

newtype Filter a b = Filter (a -> [b])

runFilter :: Filter a b -> a -> [b]
makeFilter :: (a -> [b]) -> Filter a b
apFilter :: ([a] -> [b]) -> Filter c a -> Filter c b 
aEach :: Filter [a] a

The runFilter function applies a filter to an input to produce a list of outputs; makeFilter turns a function f :: a -> [b] into a Filter makeFilter f :: Filter a b. (These two functions are inverses; in fact both are the identity.)

apFilter applies a list function f :: [a] -> [b] to a filter to produce a new filter; apFilter func filt is shorthand for makeFilter (func . runFilter filt).

Node tests

The node test filters are guards; they filter out nodes which fail to satisfy some predicate.

qElem		:: String -> Filter XML XML
qElems 		:: [String] -> Filter XML XML
qText, qEntity	:: Filter XML XML
qMatch		:: Filter x y -> Filter x x

qElem selects element nodes with a specified element type name. qElems takes a list of element type names, and selects element nodes with any of those names. qText and qEntity select text nodes and entity reference nodes, respectively.

qMatch turns an arbitrary filter into a guard: qMatch f succeeds if f returns a nonempty list when applied to the input.

Navigation

The following filters navigate down Tree structures:

qSelf, qChildren, qDescendants, qSubtree :: Filter (Tree a) (Tree a)

qSelf is the identity arrow; it corresponds to the XPath self axis. qChildren returns the immediate children of the input node, and qDescendants returns all proper descendants. qSubtree returns all of the nodes rooted at the input node; it is equivalent to the XPath descendants-or-self axis.

|>| is the ``distinguished choice'' operator: f |>| g returns the result of evaluating f if the result is nonempty, otherwise the result of evaluating g.

qOuter recursively descends the tree, applying a filter at each step, and returns the outermost nonempty result. qInner is similar, but proceeds from the bottom up:

qInner, qOuter :: Filter (Tree a) b -> Filter (Tree a) b
qOuter p = p |>| (qChildren >>> qOuter p)
qInner p = (qChildren >>> qInner p) |>| p

qFirst applies a filter and returns only the first result:

qFirst :: Filter a b -> Filter a b
qFirst f = apFilter take1 where
	take1 (x:_) = [x]
	take1 [] = []

qAttributes is an XML-specific filter that returns the attribute list of the input node. qAttribute returns the value of a specific attribute. qNodeName returns the node name of the current node; this is the element type name for elements, PI target for processing instructions, or entity name for entity reference nodes For other node types, returns nothing.

qAttributes :: Filter XML (Name, String)
qAttribute  :: Name -> Filter XML String
qNodeName   :: Filter XML Name

Constructors

mkElem    :: String -> Filter a XML -> Filter a XML
mkElement :: String -> Filter a (Name,String) -> Filter a XML -> Filter a XML
mkText    :: Filter String XML
mkLiteral :: String -> Filter a XML
mkAtt     :: Name -> Filter a String -> Filter a (Name,String)

mkElement name atts content is a filter which creates an element node with the specified name; it passes its input to the atts filter to construct the attribute list, and to the content filter to construct the list of children. mkElem is a shorthand version of mkElement for the common case where there are no attributes; it is defined as mkElem gi body = mkElement gi aZero body.

mkAtt constructs an attribute value (represented in HXML as a (name, value) pair.

mkLiteral and mkText both construct text nodes. mkText is a filter which creates a text node containing its (string) input. mkLiteral txt is equivalent to aConst txt >>> mkText.

Editing combinators

apChildren, aFoldTree, aScanTree
	:: Filter (Tree a) (Tree a) -> Filter (Tree a) (Tree a)

apChildren applies a specified filter to the children of the input tree, and replaces them with the result. aFoldTree and aScanTree recursively apply a filter to each node in the tree, aFoldTree from the bottom up and aScanTree from the top down:

aFoldTree f = apChildren (aFoldTree f) >>> f
aScanTree f = f >>> apChildren (aScanTree f)