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).
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.
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
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.
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)