HXT
From HaskellWiki
1 A Gentle Introduction to the Haskell XML Toolbox
The Haskell XML Toolbox (HXT) is a collection of tools for processing XML with Haskell. The core component of the Haskell XML Toolbox is a domain specific language consisting of a set of combinators for processing XML trees in a simple and elegant way. The combinator library is based on the concept of arrows. The main component is a validating and namespace-aware XML Parser that supports the XML 1.0 Standard almost completely. Extensions are a validator for RelaxNG and an XPath evaluator.
2. version 9.0.0.
3 Resources
3.1 Home Page and Repository
- HXT
- The project home for HXT
- HXT on GitHub
- The git source repository on github for all HXT packages
3.2.
3.2.2.
3.3.
3.4 Upgrade from HXT versions < 9.0
HXT-9 is not downwards compatible. The splitting into smaller packages required some internal reorganisation and changes of some type declarations. To use the main features of the core package, import.
4 The basic concepts
4.1]
4.2]
p :: XmlTree -> Bool -- pure function p t = ... pf :: XmlTree -> [XmlTree] -- or XmlFilter pf t | p t = [t] | otherwise = []
isA :: (a -> Bool) -> (a -> [a]) isA p x | p x = [x] | otherwise = []
As an example, a predicate for filtering text nodes looks like this:
isXText :: XmlTree -> Bool isXText (NTree (XText _) _) = True is.
4.3 Filter combinatorsComposition of filters, like function composition, is the most important combinator. We will use the infix operator
(>>>) :: XmlFilter -> XmlFilter -> XmlFilter (f >>> g) t = concat [g t' | t' <- f t]
getGrandChildren :: XmlFilter getGrandChildren = getChildren >>> getChildren
getTextChildren :: XmlFilter getTextChildren = getChildren >>> isXText
(<+>) :: XmlFilter -> XmlFilter -> XmlFilter (f <+> g) t = f t ++ g :: XmlFilter -> XmlFilter -> XmlFilter orElse f g t | null res1 = g t | otherwise = res1 where res1 = f
4.4 :: XmlFilter -> XmlFilter deep f = f `orElse` (getChildren >>> deep f)
Example: Selecting all plain text nodes of a document can be formulated with:
deep isXText
Example: Selecting all "top level" tables in a HTML documents looks like this:
deep (isElem >>> hasName "table")
multi :: XmlFilter -> XmlFilter multi f = f <+> (getChildren >>> multi f)
4.5 ArrowsWe've already seen that the filters])
A filter as discussed above has all features of an arrow. Arrows are introduced for generalizing the concept of functions and function combination to more general kinds of computation.A basic set of combinators for arrows is defined in the classes in the and last one are those used most frequently in the toolbox, and of course there are lifting functions for converting general arrows into more specific arrows. Don't worry about all these conceptual details. Let's have a look at some Hello world examples.
5 Getting started: Hello world examples
5.1 almost anything as HTML. This can be selected by using:
readDocument [withParseHTML yes, ...]
5.2.
The interesing line is (1).
all children of a node. All results form processing the list of children from the result node.
The structure of internal document tree can be made visiblee.g. by adding the option
This will emit the tree in a readable text representation instead of the real document.
In the next section we will give examples for the
5.3.
6 Selection examples
6.1 Selecting text from an HTML document
Selecting all the plain text of an XML/HTML document can be formulated with
selectAllText :: ArrowXml a => a XmlTree XmlTree selectAllText = deep isText
In this case, where the selected nodes are all leaves, these would give the same result.
6.2).
6
7 Document construction examples
7.1) ] ]
To write this document to a file use the following arrow
root [] [helloWorld] -- (1) >>> writeDocument [withIndent yes] "hello.xml" -- (2)
document is wrapped into a so called root node (1). This complete document is written to "hello.xml" (2).
a whole document tree with such a root node. Before writing, the document isindented (of the use of the constant arrow
7.2 A page about all images within a HTML page
A bit more interesting task is the construction of a page containing a table of all images within a page inclusive image URLs, geometry and ALT attributes.The program for this has a frame similar to thea simple XML contents parser called
The example above could then be rewritten as
imageTable = selem "html" [ pageHeader , ... ] where pageHeader = constA "<head><title>Images in Page</title></head>" >>> xread ...
IO monad, so it can be used in any context, but therefore the error handlingis very limited.
7.3 A page about all images within a HTML page: 1. Refinement
The next refinement step is the extension of the table such that it contains four columns, one for the image itself, one for the URL,the geometry and the ALT text. The extended
(2) is the column from the previous example but the URL has been made active by embedding the URL in an A-element (2.1). In (3) there are twonew combinators,
geometry spec. (4) adds the ALT-text.
7.4) )
(1). This arrow uses the global system state of HXT, in which the base URL of a document is stored. For editing the SRC attribute value, the attribute listof the image elements is processed with
The resulting String value is converted into a text node forming the new attribute value node (7).Because of the use of the global HXT state in
8 Transformation examples
8.1)
This arrow applies an arrow to all nodes of the whole document tree.The transformation arrow applies the
all A-elements (3),(4). This arrow uses a bit simplified test (4.1) for external URLs.
selecting the current children (6) and adding an image element (7).The image element is constructed with
an element name, a list of arrows for computing the attributes and a list of arrows for computing the contents. The content of the image element isempty (10). The attributes are constructed with
the name value pair of arguments.
8.2 traverswith combined arrow, our main arrow, looks like this:
toAbsRefs :: IOStateArrow s XmlTree XmlTree toAbsRefs = mkAbsHRefs $< computeBaseRef -- (1)
To complete the development of the example, a last step is necessary:)
computeBaseRef :: IOStateArrow s XmlTree String computeBaseRef = ( ( ( getDescendents ["html","head","base"] -- (1) >>> getAttrValue "href" -- ") ...
8.3
The arrow applied to every element is extended to a sequence of = ...
so the above code can be simplified to
mkAbsRefs :: ArrowXml a => String -> a XmlTree XmlTree mkAbsRefs base = processTopDown editRefs where editRefs = seqA . map (uncurry editRef) $ ...
9 More complex examples
9.1 Serialization and deserialisation to/from XML
Examples can be found in HXT/Conversion of Haskell data from/to XML
9.2 Practical examples of HXT
More complex and complete examples of HXT in action can be found in HXT/Practical
9.3 The Complete Guide To Working With HTML
Tutorial and Walkthrough: