text: Difference between revisions of "HXT"
  Latest revision as of 00:20, 27 April 2016 the XML 1.0 Standard almost completely. Extensions are a validator for RelaxNG and an XPath evaluator.
  Contents
  - 1 A Gentle Introduction to the Haskell XML Toolbox
  - 2 Background
  - 3 Resources
  - 4 The basic concepts
  - 5 Getting started: Hello world examples
  - 6 Selection examples
  - 7 Document construction examples
  - 8 Transformation examples
  - 9 More complex examples
  Background
  The Haskell XML Toolbox is based.
  HXT has grown over the years. Components for XPath, XSLT, validation with RelaxNG, picklers for conversion from/to native Haskell data, lazy parsing with tagsoup, input via curl and native Haskell HTTP and others have been added. This has led to a rather large package with a lot of dependencies.
  To make the toolbox more modular and to reduce the dependencies on other packages, hxt has been split into various smaller packages since version 9.0.0.
  Resources
  Home Page and Repository
  -, import
  Text.XML.HXT.Core instead of
  Text.XML.HXT.Arrow..
  The basic concepts.
  data]
  XmlFilter. To build filters from pure functions, we need a way to lift them to filters. For predicates this is done by mapping
  Falseto the empty list and
  Trueto a singleton list containing the input tree:
  p :: XmlTree -> Bool -- pure function p t = ... pf :: XmlTree -> [XmlTree] -- or XmlFilter pf t | p t = [t] | otherwise = []
  isA, and it works on any type. It is defined as:
  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 isX)]
  arr, it comes from the
  Control.Arrowmodule of the
  basepackage of GHC. Partial functions, i.e functions that can't always compute a result, are usually lifted to totally defined filters where illegal arguments are mapped to the empty list:.
  Filter combinatorsComposition of filters, like function composition, is the most important combinator. We will use the infix operator
  (>>>)for filter composition and reverse the arguments, so we can read composition sequences from left to right, like pipes in Unix. Composition is defined as follows:
  (>>>) :: XmlFilter -> XmlFilter -> XmlFilter (f >>> g) t = concat [g t' | t' <- f t]
  (>>>)operator, the definition of
  getGrandChildrenbecomes rather simple:
  getGrandChildren :: XmlFilter getGrandChildren = getChildren >>> getChildren
  (>>>):
  getTextChildren :: XmlFilter getTextChildren = getChildren >>> isXText
  (>>>)serves as a logical "and" operator or, from the relational view, as an intersection operator:
  isA p1 >>> isA p2selects all values for which p1 and p2 both hold. The dual operator to
  (>>>)is
  (<+>), the logical "or" for filters:
  (<+>) :: XmlFilter -> XmlFilter -> XmlFilter (f <+> g) t = f t ++ g t -- not literally ++, rather the set union operator -- so without duplicates
  (>>>)and
  (<+>)leads to more complex functionality. For example, selecting all text nodes within two levels of depth (in left to right order) can be formulatedand is defined as follows:
  orElse :: XmlFilter -> XmlFilter -> XmlFilter orElse f g t | null res1 = g t | otherwise = res1 where res1 = f t
  fcomputes a non-empty list as result,
  fsucceeds and this list is the result. Otherwise
  gis applied to the input, and this yields the overall result. There are two other simple choice combinators usually written in infix notation,
  g `guards` fand
  f `when` g, which are useful when transforming and manipulating trees:X multi f = f <+> (getChildren >>> multi f)
  Example: Selecting all tables in a HTML document, even nested ones,
  multi has to be used instead of
  deep:
  multi (isElem >>> hasName "table")
  ArrowsWe've already seen that the filters
  a -> [b]are a very powerful and sometimes a more elegant way to process XML than pure functions, which is the good news. The bad news is that filters are not general enough. We e.g. want to do some I/O while staying at the filter level, so for the IO monad we need something like:])
  deep,
  deepST,
  deepIO,
  deepIOST. This is the point where
  newtypes and
  classes come in. Classes are needed for overloading names and
  newtypes are needed to declare instances. Furthermore, the restriction of
  XmlTreeas the argument and result type is not necessary and hinders reuse in many cases.
  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
  Control.Arrow module, containing the above mentioned
  (>>>), (<+>) and
  arr.
  In HXT, the additional classes for filters working with lists as the result type are defined in
  Control.Arrow.ArrowList. The choice operators are in
  Control.Arrow.ArrowIf, tree filters (like
  getChildren,
  deep, or
  multi) in
  Control.Arrow.ArrowTree, and the elementary XML-specific filters in
  Text.XML.HXT.XmlArrow. 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.
  Getting started: Hello world examples ()
  runX, which executes an arrow. This arrow is one of the more powerful list arrows with IO and an HXT system state. The arrow itself is a composition of
  readDocumentand
  writeDocument.
  readDocumentmust be imported by
  import Text.XML.HXT.Curl. If only file access is necessary, this option and the import can be dropped. In that case the program does not depend on the libcurl binding. The tree is then piped into the output arrow, which is once again controlled by a set of system options. The
  withIndentoption controls the output formatting (here indentation is switched on) and the
  withOutputEncodingoption switches the output to the ISO-Latin1 encoding.
  writeDocumentconverts the tree into a string and writes it to
  dst. The available options for reading and writing can be found in the module
  Text.XML.HXT.Arrow.XmlState.SystemConfig.> < interpret almost anything as HTML. This can be selected by using:
  readDocument [withParseHTML yes, ...]
  Pattern for a main program
  A more realistic pattern for a simple Unix filter like program has the following structure:
  module Main where import Text.XML.HXT.Core import Text.XML.HXT.... -- further HXT packages .
  withShowTree yes to the
  writeDocument arrow in (3).
  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
  processDocumentRootElement arrow.. leaves, these would give the same result.).
  To write this document to a file use the following arrow
  root [] [helloWorld] -- (1) >>> writeDocument [withIndent yes]  (
  withIndent yes)) by inserting extra whitespace containing relative travers absolute absence its variants
  ($<<), ($<<<), ($<<<<), ($<$) is sufficient.
  To complete the development of the example, a last step is necessary: sub-tree technique can be found is simpler to make selections of this type, but the XPath evaluation in general is more expensive in time and space than a simple combination of arrowsas
  Serialization and deserialisation to/from XML
  Examples can be found in HXT/Conversion of Haskell data from/to XML
  Practical examples of HXT
  More complex and complete examples of HXT in action can be found in HXT/Practical
  The Complete Guide To Working With HTML
  Tutorial and Walkthrough: