packages feed

xmlhtml (empty) → 0.1

raw patch · 13 files changed

+4729/−0 lines, 13 filesdep +basedep +blaze-builderdep +blaze-htmlsetup-changed

Dependencies added: base, blaze-builder, blaze-html, bytestring, containers, parsec, text

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c)2011, Chris Smith <cdsmith@gmail.com>++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Chris Smith <cdsmith@gmail.com> nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ src/Text/Blaze/Renderer/XmlHtml.hs view
@@ -0,0 +1,74 @@+-- | Renderer that supports rendering to xmlhtml forests.  This is a port of+-- the Hexpat renderer.+--+-- Warning: because this renderer doesn't directly create the output, but rather+-- an XML tree representation, it is impossible to render pre-escaped text. This+-- means that @preEscapedString@ will produce the same output as @string@. This+-- also applies to the functions @preEscapedText@, @preEscapedTextValue@...+--+module Text.Blaze.Renderer.XmlHtml (renderHtml) where++import           Data.Text (Text)+import qualified Data.Text as T+import qualified Data.Text.Encoding as T+import           Text.Blaze.Internal+import           Text.XmlHtml+++-- | Render a 'ChoiceString' to Text. This is only meant to be used for+-- shorter strings, since it is inefficient for large strings.+--+fromChoiceStringText :: ChoiceString -> Text+fromChoiceStringText (Static s)               = getText s+fromChoiceStringText (String s)               = T.pack s+fromChoiceStringText (Text s)                 = s+fromChoiceStringText (ByteString s)           = T.decodeUtf8 s+fromChoiceStringText (PreEscaped s)           = fromChoiceStringText s+fromChoiceStringText (External s)             = fromChoiceStringText s+fromChoiceStringText (AppendChoiceString x y) =+    fromChoiceStringText x `T.append` fromChoiceStringText y+fromChoiceStringText EmptyChoiceString        = T.empty+{-# INLINE fromChoiceStringText #-}+++-- | Render a 'ChoiceString' to an appending list of nodes+--+fromChoiceString :: ChoiceString -> [Node] -> [Node]+fromChoiceString s@(Static _)     = (TextNode (fromChoiceStringText s) :)+fromChoiceString s@(String _)     = (TextNode (fromChoiceStringText s) :)+fromChoiceString s@(Text _)       = (TextNode (fromChoiceStringText s) :)+fromChoiceString s@(ByteString _) = (TextNode (fromChoiceStringText s) :)+fromChoiceString (PreEscaped s)   = fromChoiceString s+fromChoiceString (External s)     = fromChoiceString s+fromChoiceString (AppendChoiceString x y) =+    fromChoiceString x . fromChoiceString y+fromChoiceString EmptyChoiceString = id+{-# INLINE fromChoiceString #-}+++-- | Render some 'Html' to an appending list of nodes+--+renderNodes :: Html -> [Node] -> [Node]+renderNodes = go []+  where+    go :: [(Text, Text)] -> HtmlM b -> [Node] -> [Node]+    go attrs (Parent tag _ _ content) =+        (Element (getText tag) attrs (go [] content []) :)+    go attrs (Leaf tag _ _) =+        (Element (getText tag) attrs [] :)+    go attrs (AddAttribute key _ value content) =+        go ((getText key, fromChoiceStringText value) : attrs) content+    go attrs (AddCustomAttribute key _ value content) =+        go ((fromChoiceStringText key, fromChoiceStringText value) : attrs) content+    go _ (Content content) = fromChoiceString content+    go attrs (Append h1 h2) = go attrs h1 . go attrs h2+    go _ Empty = id+    {-# NOINLINE go #-}+{-# INLINE renderNodes #-}++-- | Render HTML to an xmlhtml Document+--+renderHtml :: Html -> Document+renderHtml html = HtmlDocument UTF8 Nothing (renderNodes html [])+{-# INLINE renderHtml #-}+
+ src/Text/XmlHtml.hs view
@@ -0,0 +1,93 @@+------------------------------------------------------------------------------+-- | Parsers and renderers for XML and HTML 5.  Although the formats are+--   treated differently, the data types used by each are the same, which+--   makes it easy to write code that works with the element structure of+--   either XML or HTML 5 documents.+--+--   Limitations:+--+--   * The XML parser does not parse internal DOCTYPE subsets.  They are just+--     stored as blocks of text, with minimal scanning done to match quotes+--     and brackets to determine the end.+--+--   * Since DTDs are not parsed, the XML parser fails on entity references,+--     except for those defined internally.  You cannot use this library for+--     parsing XML documents with entity references outside the predefined set.+--+--   * The HTML 5 parser is not a compliant HTML parser.  Instead, it is a+--     parser for valid HTML 5 content.  It should only be used on content+--     that you have reason to believe is probably correct, since the+--     compatibility features of HTML 5 are missing.  This is the wrong+--     library on which to build a web spider.+--+--   * Both parsers accept fragments of documents, by which is meant that+--     they do not enforce the top-level structure of the document.  Files+--     may contain more than one root element, for example.+module Text.XmlHtml (+    -- * Types+    Document(..),+    Node(..),+    DocType(..),+    ExternalID(..),+    InternalSubset(..),+    Encoding(..),++    -- * Manipulating documents+    isTextNode,+    isComment,+    isElement,+    tagName,+    getAttribute,+    hasAttribute,+    setAttribute,+    nodeText,+    childNodes,+    childElements,+    childElementsTag,+    childElementTag,+    descendantNodes,+    descendantElements,+    descendantElementsTag,+    descendantElementTag,++    -- * Parsing+    parseXML,+    parseHTML,++    -- * Rendering+    render+    ) where++------------------------------------------------------------------------------+import           Blaze.ByteString.Builder (Builder)+import           Data.ByteString (ByteString)++import           Text.XmlHtml.Common+import           Text.XmlHtml.TextParser++import qualified Text.XmlHtml.XML.Parse as XML+import qualified Text.XmlHtml.XML.Render as XML++import qualified Text.XmlHtml.HTML.Parse as HTML+import qualified Text.XmlHtml.HTML.Render as HTML+++------------------------------------------------------------------------------+-- | Parses the given XML fragment.+parseXML :: String -> ByteString -> Either String Document+parseXML = parse XML.docFragment+++------------------------------------------------------------------------------+-- | Parses the given HTML fragment.  This enables HTML quirks mode, which+--   changes the parsing algorithm to parse valid HTML 5 documents correctly.+parseHTML :: String -> ByteString -> Either String Document+parseHTML = parse HTML.docFragment+++------------------------------------------------------------------------------+-- | Renders a 'Document'.+render :: Document -> Builder+render (XmlDocument  e dt ns) = XML.render  e dt ns+render (HtmlDocument e dt ns) = HTML.render e dt ns+
+ src/Text/XmlHtml/Common.hs view
@@ -0,0 +1,225 @@+{-# LANGUAGE OverloadedStrings     #-}+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE MultiParamTypeClasses #-}++module Text.XmlHtml.Common where++import           Blaze.ByteString.Builder+import           Data.Maybe++import           Data.Text (Text)+import qualified Data.Text as T+import qualified Data.Text.Encoding as T+import qualified Data.Text.Encoding.Error as TE++import           Data.ByteString (ByteString)+++------------------------------------------------------------------------------+-- | Represents a document fragment, including the format, encoding, and+-- document type declaration as well as its content.+data Document = XmlDocument  {+                    docEncoding :: !Encoding,+                    docType     :: !(Maybe DocType),+                    docContent  :: ![Node]+                }+              | HtmlDocument {+                    docEncoding :: !Encoding,+                    docType     :: !(Maybe DocType),+                    docContent  :: ![Node]+                }+    deriving (Eq, Show)+++------------------------------------------------------------------------------+-- | A node of a document structure.  A node can be text, a comment, or an+-- element.  XML processing instructions are intentionally omitted as a+-- simplification, and CDATA and plain text are both text nodes, since they+-- ought to be semantically interchangeable.+data Node = TextNode !Text+          | Comment  !Text+          | Element {+                elementTag      :: !Text,+                elementAttrs    :: ![(Text, Text)],+                elementChildren :: ![Node]+            }+    deriving (Eq, Show)+++------------------------------------------------------------------------------+-- | Determines whether the node is text or not.+isTextNode :: Node -> Bool+isTextNode (TextNode _) = True+isTextNode _            = False+++------------------------------------------------------------------------------+-- | Determines whether the node is a comment or not.+isComment :: Node -> Bool+isComment (Comment _) = True+isComment _           = False+++------------------------------------------------------------------------------+-- | Determines whether the node is an element or not.+isElement :: Node -> Bool+isElement (Element _ _ _) = True+isElement _               = False+++------------------------------------------------------------------------------+-- | Gives the tag name of an element, or 'Nothing' if the node isn't an+-- element.+tagName :: Node -> Maybe Text+tagName (Element t _ _) = Just t+tagName _               = Nothing+++------------------------------------------------------------------------------+-- | Retrieves the attribute with the given name.  If the 'Node' is not an+-- element, the result is always 'Nothing'+getAttribute :: Text -> Node -> Maybe Text+getAttribute name (Element _ attrs _) = lookup name attrs+getAttribute _    _                   = Nothing+++------------------------------------------------------------------------------+-- | Checks if a given attribute exists in a 'Node'.+hasAttribute :: Text -> Node -> Bool+hasAttribute name = isJust . getAttribute name+++------------------------------------------------------------------------------+-- | Sets the attribute name to the given value.  If the 'Node' is not an+-- element, this is the identity.+setAttribute :: Text -> Text -> Node -> Node+setAttribute name val (Element t a c) = Element t newAttrs c+  where newAttrs = (name, val) : filter ((/= name) . fst) a+setAttribute _    _   n                   = n+++------------------------------------------------------------------------------+-- | Gives the entire text content of a node, ignoring markup.+nodeText :: Node -> Text+nodeText (TextNode t)    = t+nodeText (Comment _)     = ""+nodeText (Element _ _ c) = T.concat (map nodeText c)+++------------------------------------------------------------------------------+-- | Gives the child nodes of the given node.  Only elements have child nodes.+childNodes :: Node -> [Node]+childNodes (Element _ _ c) = c+childNodes _               = []+++------------------------------------------------------------------------------+-- | Gives the child elements of the given node.+childElements :: Node -> [Node]+childElements = filter isElement . childNodes+++------------------------------------------------------------------------------+-- | Gives all of the child elements of the node with the given tag+-- name.+childElementsTag :: Text -> Node -> [Node]+childElementsTag tag = filter ((== Just tag) . tagName) . childNodes+++------------------------------------------------------------------------------+-- | Gives the first child element of the node with the given tag name,+-- or 'Nothing' if there is no such child element.+childElementTag :: Text -> Node -> Maybe Node+childElementTag tag = listToMaybe . childElementsTag tag+++------------------------------------------------------------------------------+-- | Gives the descendants of the given node in the order that they begin in+-- the document.+descendantNodes :: Node -> [Node]+descendantNodes = concatMap (\n -> n : descendantNodes n) . childNodes++------------------------------------------------------------------------------+-- | Gives the descendant elements of the given node, in the order that their+-- start tags appear in the document.+descendantElements :: Node -> [Node]+descendantElements = filter isElement . descendantNodes+++------------------------------------------------------------------------------+-- | Gives the descendant elements with a given tag name.+descendantElementsTag :: Text -> Node -> [Node]+descendantElementsTag tag = filter ((== Just tag) . tagName) . descendantNodes+++------------------------------------------------------------------------------+-- | Gives the first descendant element of the node with the given tag name,+-- or 'Nothing' if there is no such element.+descendantElementTag :: Text -> Node -> Maybe Node+descendantElementTag tag = listToMaybe . descendantElementsTag tag+++------------------------------------------------------------------------------+-- | A document type declaration.  Note that DTD internal subsets are+-- currently unimplemented.+data DocType = DocType !Text !ExternalID !InternalSubset+    deriving (Eq, Show)+++------------------------------------------------------------------------------+-- | An external ID, as in a document type declaration.  This can be a+-- SYSTEM identifier, or a PUBLIC identifier, or can be omitted.+data ExternalID = Public !Text !Text+                | System !Text+                | NoExternalID+    deriving (Eq, Show)+++------------------------------------------------------------------------------+-- | The internal subset is unparsed, but preserved in case it's actually+-- wanted.+data InternalSubset = InternalText !Text+                    | NoInternalSubset+    deriving (Eq, Show)+++------------------------------------------------------------------------------+-- | The character encoding of a document.  Currently only the required+-- character encodings are implemented.+data Encoding = UTF8 | UTF16BE | UTF16LE deriving (Eq, Show)+++------------------------------------------------------------------------------+-- | Retrieves the preferred name of a character encoding for embedding in+-- a document.+encodingName :: Encoding -> Text+encodingName UTF8    = "UTF-8"+encodingName UTF16BE = "UTF-16"+encodingName UTF16LE = "UTF-16"+++------------------------------------------------------------------------------+-- | Gets the encoding function from 'Text' to 'ByteString' for an encoding.+encoder :: Encoding -> Text -> ByteString+encoder UTF8    = T.encodeUtf8+encoder UTF16BE = T.encodeUtf16BE+encoder UTF16LE = T.encodeUtf16LE+++------------------------------------------------------------------------------+-- | Gets the decoding function from 'ByteString' to 'Text' for an encoding.+decoder :: Encoding -> ByteString -> Text+decoder UTF8    = T.decodeUtf8With    (TE.replace '\xFFFF')+decoder UTF16BE = T.decodeUtf16BEWith (TE.replace '\xFFFF')+decoder UTF16LE = T.decodeUtf16LEWith (TE.replace '\xFFFF')+++------------------------------------------------------------------------------+isUTF16 :: Encoding -> Bool+isUTF16 e = e == UTF16BE || e == UTF16LE+++------------------------------------------------------------------------------+fromText :: Encoding -> Text -> Builder+fromText e t = fromByteString (encoder e t)+
+ src/Text/XmlHtml/Cursor.hs view
@@ -0,0 +1,409 @@+------------------------------------------------------------------------------+-- | A zipper for navigating and modifying XML trees.  This is nearly the+-- same exposed interface as the @xml@ package in @Text.XML.Light.Cursor@,+-- with modifications as needed to adapt to different types.+module Text.XmlHtml.Cursor (+    -- * Cursor type+    Cursor,++    -- * Conversion to and from cursors+    fromNode,+    fromNodes,+    topNode,+    topNodes,+    current,+    siblings,++    -- * Cursor navigation+    parent,+    root,+    getChild,+    firstChild,+    lastChild,+    left,+    right,+    nextDF,++    -- * Search+    findChild,+    findLeft,+    findRight,+    findRec,++    -- * Node classification+    isRoot,+    isFirst,+    isLast,+    isLeaf,+    isChild,+    hasChildren,+    getNodeIndex,++    -- * Updates+    setNode,+    modifyNode,+    modifyNodeM,++    -- * Insertions+    insertLeft,+    insertRight,+    insertManyLeft,+    insertManyRight,+    insertFirstChild,+    insertLastChild,+    insertManyFirstChild,+    insertManyLastChild,+    insertGoLeft,+    insertGoRight,+    +    -- * Deletions+    removeLeft,+    removeRight,+    removeGoLeft,+    removeGoRight,+    removeGoUp+    ) where++import           Control.Monad+import           Data.Maybe+import           Data.Text (Text)+import           Text.XmlHtml++------------------------------------------------------------------------------+-- | Just the tag of an element+type Tag = (Text, [(Text, Text)])+++------------------------------------------------------------------------------+-- | Reconstructs an element from a tag and a list of its children.+fromTag :: Tag -> [Node] -> Node+fromTag (t,a) c = Element t a c+++------------------------------------------------------------------------------+-- | A zipper for XML document forests.+data Cursor = Cursor {+    current :: !Node,   -- ^ Retrieves the current node of a 'Cursor'+    lefts   :: ![Node],                 -- right to left+    rights  :: ![Node],                 -- left to right+    parents :: ![([Node], Tag, [Node])] -- parent's tag and siblings+    }+    deriving (Eq)+++------------------------------------------------------------------------------+-- | Builds a 'Cursor' for navigating a tree. That is, a forest with a single+-- root 'Node'.+fromNode :: Node -> Cursor+fromNode n = Cursor n [] [] []+++------------------------------------------------------------------------------+-- | Builds a 'Cursor' for navigating a forest with the given list of roots.+-- The cursor is initially positioned at the left-most node.  Gives 'Nothing'+-- if the list is empty.+fromNodes :: [Node] -> Maybe Cursor+fromNodes (n:ns) = Just (Cursor n [] ns [])+fromNodes []     = Nothing+++------------------------------------------------------------------------------+-- | Retrieves the root node containing the current cursor position.+topNode :: Cursor -> Node+topNode cur  = current (root cur)+++------------------------------------------------------------------------------+-- | Retrieves the entire forest of 'Node's corresponding to a 'Cursor'.+topNodes :: Cursor -> [Node]+topNodes cur = siblings (root cur)+++------------------------------------------------------------------------------+-- | Retrieves a list of the 'Node's at the same level as the current position+-- of a cursor, including the current node.+siblings :: Cursor -> [Node]+siblings (Cursor cur ls rs _) = foldl (flip (:)) (cur:rs) ls+++------------------------------------------------------------------------------+-- | Navigates a 'Cursor' to its parent in the document.+parent :: Cursor -> Maybe Cursor+parent c@(Cursor _ _ _ ((ls,t,rs):ps))+            = Just (Cursor (fromTag t (siblings c)) ls rs ps)+parent _    = Nothing+++------------------------------------------------------------------------------+-- | Navigates a 'Cursor' up through parents to reach the root level.+root :: Cursor -> Cursor+root = until isRoot (fromJust . parent)+++------------------------------------------------------------------------------+-- | Navigates a 'Cursor' down to the indicated child index.+getChild :: Int -> Cursor -> Maybe Cursor+getChild i (Cursor n ls rs ps) =+    case n of+      Element t a cs -> let (lls, rest) = splitAt i cs in+          if i >= length cs+            then Nothing+            else Just $ Cursor (head rest)+                               (reverse lls)+                               (tail rest)+                               ((ls, (t,a), rs):ps)+      _              -> Nothing+++------------------------------------------------------------------------------+-- | Navigates a 'Cursor' down to its first child.+firstChild :: Cursor -> Maybe Cursor+firstChild = getChild 0+++------------------------------------------------------------------------------+-- | Navigates a 'Cursor' down to its last child.+lastChild :: Cursor -> Maybe Cursor+lastChild (Cursor (Element t a c) ls rs ps) | not (null c)+    = let rc = reverse c+      in  Just $ Cursor (head rc) (tail rc) [] ((ls, (t,a), rs):ps)+lastChild _+    = Nothing+++------------------------------------------------------------------------------+-- | Moves a 'Cursor' to its left sibling.+left :: Cursor -> Maybe Cursor+left (Cursor c (l:ls) rs ps) = Just (Cursor l ls (c:rs) ps)+left _                       = Nothing+++------------------------------------------------------------------------------+-- | Moves a 'Cursor' to its right sibling.+right :: Cursor -> Maybe Cursor+right (Cursor c ls (r:rs) ps) = Just (Cursor r (c:ls) rs ps)+right _                       = Nothing+++------------------------------------------------------------------------------+-- | Moves a 'Cursor' to the next node encountered in a depth-first search.+-- If it has children, this is equivalent to 'firstChild'.  Otherwise, if it+-- has a right sibling, then this is equivalent to 'right'.  Otherwise, the+-- cursor moves to the first right sibling of one of its parents.+nextDF :: Cursor -> Maybe Cursor+nextDF c = firstChild c `mplus` up c+  where up x = right x `mplus` (up =<< parent x)+++------------------------------------------------------------------------------+-- | Repeats the given move until a 'Cursor' is obtained that matches the+-- predicate.+search :: (Cursor -> Bool)         -- ^ predicate+       -> (Cursor -> Maybe Cursor) -- ^ move+       -> Cursor                   -- ^ starting point+       -> Maybe Cursor+search p move c | p c       = return c+                | otherwise = search p move =<< move c+++------------------------------------------------------------------------------+-- | Navigates a 'Cursor' to the first child that matches the predicate.+findChild :: (Cursor -> Bool) -> Cursor -> Maybe Cursor+findChild p cur = search p right =<< firstChild cur+++------------------------------------------------------------------------------+-- | Navigates a 'Cursor' to the nearest left sibling that matches a+-- predicate.+findLeft :: (Cursor -> Bool) -> Cursor -> Maybe Cursor+findLeft p cur = search p left =<< left cur+++------------------------------------------------------------------------------+-- | Navigates a 'Cursor' to the nearest right sibling that matches a predicate.+findRight :: (Cursor -> Bool) -> Cursor -> Maybe Cursor+findRight p cur = search p right =<< right cur+++------------------------------------------------------------------------------+-- | Does a depth-first search for a descendant matching the predicate.  This+-- can match the current cursor position.+findRec :: (Cursor -> Bool) -> Cursor -> Maybe Cursor+findRec p = search p nextDF+++------------------------------------------------------------------------------+-- | Determines if the 'Cursor' is at a root node.+isRoot :: Cursor -> Bool+isRoot cur = null (parents cur)+++------------------------------------------------------------------------------+-- | Determines if the 'Cursor' is at a first child.+isFirst :: Cursor -> Bool+isFirst cur = null (lefts cur)+++------------------------------------------------------------------------------+-- | Determines if the 'Cursor' is at a last child.+isLast :: Cursor -> Bool+isLast cur = null (rights cur)+++------------------------------------------------------------------------------+-- | Determines if the 'Cursor' is at a leaf node.+isLeaf :: Cursor -> Bool+isLeaf (Cursor (Element _ _ c) _ _ _) = null c+isLeaf _                              = True+++------------------------------------------------------------------------------+-- | Determines if the 'Cursor' is at a child node (i.e., if it has a parent).+isChild :: Cursor -> Bool+isChild = not . isRoot+++------------------------------------------------------------------------------+-- | Determines if the 'Cursor' is at a non-leaf node (i.e., if it has+-- children).+hasChildren :: Cursor -> Bool+hasChildren = not . isLeaf+++------------------------------------------------------------------------------+-- | Gets the index of the 'Cursor' among its siblings.+getNodeIndex :: Cursor -> Int+getNodeIndex cur = length (lefts cur)+++------------------------------------------------------------------------------+-- | Replaces the current node.+setNode :: Node -> Cursor -> Cursor+setNode n cur = cur { current = n }+++------------------------------------------------------------------------------+-- | Modifies the current node by applying a function.+modifyNode :: (Node -> Node) -> Cursor -> Cursor+modifyNode f cur = setNode (f (current cur)) cur+++------------------------------------------------------------------------------+-- | Modifies the current node by applying an action in some functor.+modifyNodeM :: Functor m => (Node -> m Node) -> Cursor -> m Cursor+modifyNodeM f cur = flip setNode cur `fmap` f (current cur)+++------------------------------------------------------------------------------+-- | Inserts a new 'Node' to the left of the current position.+insertLeft :: Node -> Cursor -> Cursor+insertLeft n (Cursor nn ls rs ps) = Cursor nn (n:ls) rs ps+++------------------------------------------------------------------------------+-- | Inserts a new 'Node' to the right of the current position.+insertRight :: Node -> Cursor -> Cursor+insertRight n (Cursor nn ls rs ps) = Cursor nn ls (n:rs) ps+++------------------------------------------------------------------------------+-- | Inserts a list of new 'Node's to the left of the current position.+insertManyLeft :: [Node] -> Cursor -> Cursor+insertManyLeft ns (Cursor nn ls rs ps) = Cursor nn (reverse ns ++ ls) rs ps+++------------------------------------------------------------------------------+-- | Inserts a list of new 'Node's to the right of the current position.+insertManyRight :: [Node] -> Cursor -> Cursor+insertManyRight ns (Cursor nn ls rs ps) = Cursor nn ls (ns ++ rs) ps+++------------------------------------------------------------------------------+-- | Inserts a 'Node' as the first child of the current element.+insertFirstChild :: Node -> Cursor -> Maybe Cursor+insertFirstChild n (Cursor (Element t a c) ls rs ps)+    = Just (Cursor (Element t a (n:c)) ls rs ps)+insertFirstChild _ _+    = Nothing+++------------------------------------------------------------------------------+-- | Inserts a 'Node' as the last child of the current element.+insertLastChild :: Node -> Cursor -> Maybe Cursor+insertLastChild n (Cursor (Element t a c) ls rs ps)+    = Just (Cursor (Element t a (c ++ [n])) ls rs ps)+insertLastChild _ _+    = Nothing+++------------------------------------------------------------------------------+-- | Inserts a list of 'Node's as the first children of the current element.+insertManyFirstChild :: [Node] -> Cursor -> Maybe Cursor+insertManyFirstChild ns (Cursor (Element t a c) ls rs ps)+    = Just (Cursor (Element t a (ns ++ c)) ls rs ps)+insertManyFirstChild _ _+    = Nothing+++------------------------------------------------------------------------------+-- | Inserts a list of 'Node's as the last children of the current element.+insertManyLastChild :: [Node] -> Cursor -> Maybe Cursor+insertManyLastChild ns (Cursor (Element t a c) ls rs ps)+    = Just (Cursor (Element t a (c ++ ns)) ls rs ps)+insertManyLastChild _ _+    = Nothing+++------------------------------------------------------------------------------+-- | Inserts a new 'Node' to the left of the current position, and moves+-- left to the new node.+insertGoLeft :: Node -> Cursor -> Cursor+insertGoLeft n (Cursor nn ls rs ps) = Cursor n ls (nn:rs) ps+++------------------------------------------------------------------------------+-- | Inserts a new 'Node' to the right of the current position, and moves+-- right to the new node.+insertGoRight :: Node -> Cursor -> Cursor+insertGoRight n (Cursor nn ls rs ps) = Cursor n (nn:ls) rs ps+++------------------------------------------------------------------------------+-- | Removes the 'Node' to the left of the current position, if any.+removeLeft :: Cursor -> Maybe (Node, Cursor)+removeLeft (Cursor n (l:ls) rs ps) = Just (l, Cursor n ls rs ps)+removeLeft _                       = Nothing+++------------------------------------------------------------------------------+-- | Removes the 'Node' to the right of the current position, if any.+removeRight :: Cursor -> Maybe (Node, Cursor)+removeRight (Cursor n ls (r:rs) ps) = Just (r, Cursor n ls rs ps)+removeRight _                       = Nothing+++------------------------------------------------------------------------------+-- | Removes the current 'Node', and moves the Cursor to its left sibling,+-- if any.+removeGoLeft :: Cursor -> Maybe Cursor+removeGoLeft (Cursor _ (l:ls) rs ps) = Just (Cursor l ls rs ps)+removeGoLeft _                       = Nothing+++------------------------------------------------------------------------------+-- | Removes the current 'Node', and moves the Cursor to its right sibling,+-- if any.+removeGoRight :: Cursor -> Maybe Cursor+removeGoRight (Cursor _ ls (r:rs) ps) = Just (Cursor r ls rs ps)+removeGoRight _                       = Nothing+++------------------------------------------------------------------------------+-- | Removes the current 'Node', and moves the Cursor to its parent, if any.+removeGoUp :: Cursor -> Maybe Cursor+removeGoUp (Cursor _ ls rs ((lls, (t,a), rrs):ps))+    = Just (Cursor (Element t a children) lls rrs ps)+  where+    children = foldl (flip (:)) (rs) ls+removeGoUp _                       = Nothing+
+ src/Text/XmlHtml/HTML/Meta.hs view
@@ -0,0 +1,2431 @@+{-# OPTIONS_GHC -O0 -fno-case-merge -fno-strictness -fno-cse #-}+{-# LANGUAGE OverloadedStrings #-}++module Text.XmlHtml.HTML.Meta where++import           Data.Monoid+import           Data.Map (Map)+import qualified Data.Map as M+import           Data.Set (Set)+import qualified Data.Set as S+import           Data.Text (Text)++------------------------------------------------------------------------------+-- Metadata used for HTML5 quirks mode.                                     --+------------------------------------------------------------------------------++voidTags :: Set Text+voidTags = S.fromAscList [+    "area", "base", "br", "col", "command", "embed", "hr", "img", "input",+    "keygen", "link", "meta", "param", "source", "track", "wbr"+    ]++rawTextTags :: Set Text+rawTextTags = S.fromAscList [ "script", "style" ]++rcdataTags :: Set Text+rcdataTags = S.fromAscList [ "textarea", "title" ]++------------------------------------------------------------------------------+-- | Tags which can be implicitly ended in case they are the last element in+-- their parent.  This list actually includes all of the elements that have+-- any kind of omittable end tag, since in general when an element with an+-- omittable end tag isn't specified to be omittable in this way, it's just+-- because in a complete document it isn't expected to ever be the last thing+-- in its parent.  We aren't interested in enforcing element structure rules,+-- so we'll allow it anyway.+endOmittableLast :: Set Text+endOmittableLast = S.fromAscList [+    "body", "colgroup", "dd", "dt", "head", "html", "li", "optgroup",+    "option", "p", "rp", "rt", "tbody", "td", "tfoot", "th", "thead", "tr"+    ]++------------------------------------------------------------------------------+-- | Tags which should be considered automatically ended in case one of a+-- certain set of tags pops up.+endOmittableNext :: Map Text (Set Text)+endOmittableNext = M.fromAscList [+    ("colgroup", S.fromAscList ["caption", "colgroup", "tbody",+                                "thead", "tfoot", "tr"]),+    ("dd",       S.fromAscList ["dd", "dt"]),+    ("dt",       S.fromAscList ["dd", "dt"]),+    ("head",     S.fromAscList ["body"]),+    ("li",       S.fromAscList ["li"]),+    ("optgroup", S.fromAscList ["optgroup"]),+    ("option",   S.fromAscList ["optgroup", "option"]),+    ("p",        S.fromAscList ["address", "article", "aside", "blockquote",+                                "dir", "div", "dl", "fieldset", "footer",+                                "form", "h1", "h2", "h3", "h4", "h5", "h6",+                                "header", "hgroup", "hr", "menu", "nav", "ol",+                                "p", "pre", "section", "table", "ul"]),+    ("rp",       S.fromAscList ["rp", "rt"]),+    ("rt",       S.fromAscList ["rp", "rt"]),+    ("tbody",    S.fromAscList ["tbody", "tfoot", "thead"]),+    ("td",       S.fromAscList ["td", "th"]),+    ("tfoot",    S.fromAscList ["tbody", "tfoot", "thead"]),+    ("th",       S.fromAscList ["td", "th"]),+    ("thead",    S.fromAscList ["tbody", "tfoot", "thead"]),+    ("tr",       S.fromAscList ["tr"])+    ]++predefinedRefs :: Map Text Text+predefinedRefs = mconcat $ map M.fromAscList [+      reftab1+    , reftab2+    , reftab3+    , reftab4+    , reftab5+    , reftab6+    , reftab7+    , reftab8+    , reftab9+    , reftab10+    , reftab11+    , reftab12+    , reftab13+    , reftab14+    , reftab15+    , reftab16+    , reftab17+    , reftab18+    , reftab19+    , reftab20+    , reftab21+    , reftab22+    , reftab23+    , reftab24+    , reftab25+    , reftab26+    , reftab27+    , reftab28+    , reftab29+    , reftab30+    , reftab31+    , reftab32+    , reftab33+    , reftab34+    , reftab35+    , reftab36+    , reftab37+    , reftab38+    , reftab39+    , reftab40+    , reftab41+    , reftab42+    , reftab43+    , reftab44+    , reftab45+    , reftab46+    , reftab47+    , reftab48+    , reftab49+    , reftab50+    , reftab51+    , reftab52+    , reftab53+    , reftab54+    , reftab55+    , reftab56+    , reftab57+    , reftab58 ]+++reftab1 :: [(Text,Text)]+reftab1 =+  [ ("AElig", "\x000C6"),+    ("AMP", "\x00026"),+    ("Aacute", "\x000C1"),+    ("Abreve", "\x00102"),+    ("Acirc", "\x000C2"),+    ("Acy", "\x00410"),+    ("Afr", "\x1D504"),+    ("Agrave", "\x000C0"),+    ("Alpha", "\x00391"),+    ("Amacr", "\x00100"),+    ("And", "\x02A53"),+    ("Aogon", "\x00104"),+    ("Aopf", "\x1D538"),+    ("ApplyFunction", "\x02061"),+    ("Aring", "\x000C5"),+    ("Ascr", "\x1D49C"),+    ("Assign", "\x02254"),+    ("Atilde", "\x000C3"),+    ("Auml", "\x000C4"),+    ("Backslash", "\x02216"),+    ("Barv", "\x02AE7"),+    ("Barwed", "\x02306"),+    ("Bcy", "\x00411"),+    ("Because", "\x02235"),+    ("Bernoullis", "\x0212C"),+    ("Beta", "\x00392"),+    ("Bfr", "\x1D505"),+    ("Bopf", "\x1D539"),+    ("Breve", "\x002D8"),+    ("Bscr", "\x0212C"),+    ("Bumpeq", "\x0224E"),+    ("CHcy", "\x00427"),+    ("COPY", "\x000A9"),+    ("Cacute", "\x00106"),+    ("Cap", "\x022D2"),+    ("CapitalDifferentialD", "\x02145"),+    ("Cayleys", "\x0212D") ]++reftab2 :: [(Text,Text)]+reftab2 =+  [ ("Ccaron", "\x0010C"),+    ("Ccedil", "\x000C7"),+    ("Ccirc", "\x00108"),+    ("Cconint", "\x02230"),+    ("Cdot", "\x0010A"),+    ("Cedilla", "\x000B8"),+    ("CenterDot", "\x000B7"),+    ("Cfr", "\x0212D"),+    ("Chi", "\x003A7"),+    ("CircleDot", "\x02299"),+    ("CircleMinus", "\x02296"),+    ("CirclePlus", "\x02295"),+    ("CircleTimes", "\x02297"),+    ("ClockwiseContourIntegral", "\x02232"),+    ("CloseCurlyDoubleQuote", "\x0201D"),+    ("CloseCurlyQuote", "\x02019"),+    ("Colon", "\x02237"),+    ("Colone", "\x02A74"),+    ("Congruent", "\x02261"),+    ("Conint", "\x0222F"),+    ("ContourIntegral", "\x0222E"),+    ("Copf", "\x02102"),+    ("Coproduct", "\x02210"),+    ("CounterClockwiseContourIntegral", "\x02233"),+    ("Cross", "\x02A2F"),+    ("Cscr", "\x1D49E"),+    ("Cup", "\x022D3"),+    ("CupCap", "\x0224D"),+    ("DD", "\x02145"),+    ("DDotrahd", "\x02911"),+    ("DJcy", "\x00402"),+    ("DScy", "\x00405"),+    ("DZcy", "\x0040F"),+    ("Dagger", "\x02021"),+    ("Darr", "\x021A1"),+    ("Dashv", "\x02AE4"),+    ("Dcaron", "\x0010E") ]++reftab3 :: [(Text,Text)]+reftab3 =+  [ ("Dcy", "\x00414"),+    ("Del", "\x02207"),+    ("Delta", "\x00394"),+    ("Dfr", "\x1D507"),+    ("DiacriticalAcute", "\x000B4"),+    ("DiacriticalDot", "\x002D9"),+    ("DiacriticalDoubleAcute", "\x002DD"),+    ("DiacriticalGrave", "\x00060"),+    ("DiacriticalTilde", "\x002DC"),+    ("Diamond", "\x022C4"),+    ("DifferentialD", "\x02146"),+    ("Dopf", "\x1D53B"),+    ("Dot", "\x000A8"),+    ("DotDot", "\x020DC"),+    ("DotEqual", "\x02250"),+    ("DoubleContourIntegral", "\x0222F"),+    ("DoubleDot", "\x000A8"),+    ("DoubleDownArrow", "\x021D3"),+    ("DoubleLeftArrow", "\x021D0"),+    ("DoubleLeftRightArrow", "\x021D4"),+    ("DoubleLeftTee", "\x02AE4"),+    ("DoubleLongLeftArrow", "\x027F8"),+    ("DoubleLongLeftRightArrow", "\x027FA"),+    ("DoubleLongRightArrow", "\x027F9"),+    ("DoubleRightArrow", "\x021D2"),+    ("DoubleRightTee", "\x022A8"),+    ("DoubleUpArrow", "\x021D1"),+    ("DoubleUpDownArrow", "\x021D5"),+    ("DoubleVerticalBar", "\x02225"),+    ("DownArrow", "\x02193"),+    ("DownArrowBar", "\x02913"),+    ("DownArrowUpArrow", "\x021F5"),+    ("DownBreve", "\x00311"),+    ("DownLeftRightVector", "\x02950"),+    ("DownLeftTeeVector", "\x0295E"),+    ("DownLeftVector", "\x021BD"),+    ("DownLeftVectorBar", "\x02956") ]++reftab4 :: [(Text,Text)]+reftab4 =+  [ ("DownRightTeeVector", "\x0295F"),+    ("DownRightVector", "\x021C1"),+    ("DownRightVectorBar", "\x02957"),+    ("DownTee", "\x022A4"),+    ("DownTeeArrow", "\x021A7"),+    ("Downarrow", "\x021D3"),+    ("Dscr", "\x1D49F"),+    ("Dstrok", "\x00110"),+    ("ENG", "\x0014A"),+    ("ETH", "\x000D0"),+    ("Eacute", "\x000C9"),+    ("Ecaron", "\x0011A"),+    ("Ecirc", "\x000CA"),+    ("Ecy", "\x0042D"),+    ("Edot", "\x00116"),+    ("Efr", "\x1D508"),+    ("Egrave", "\x000C8"),+    ("Element", "\x02208"),+    ("Emacr", "\x00112"),+    ("EmptySmallSquare", "\x025FB"),+    ("EmptyVerySmallSquare", "\x025AB"),+    ("Eogon", "\x00118"),+    ("Eopf", "\x1D53C"),+    ("Epsilon", "\x00395"),+    ("Equal", "\x02A75"),+    ("EqualTilde", "\x02242"),+    ("Equilibrium", "\x021CC"),+    ("Escr", "\x02130"),+    ("Esim", "\x02A73"),+    ("Eta", "\x00397"),+    ("Euml", "\x000CB"),+    ("Exists", "\x02203"),+    ("ExponentialE", "\x02147"),+    ("Fcy", "\x00424"),+    ("Ffr", "\x1D509"),+    ("FilledSmallSquare", "\x025FC"),+    ("FilledVerySmallSquare", "\x025AA") ]++reftab5 :: [(Text,Text)]+reftab5 =+  [ ("Fopf", "\x1D53D"),+    ("ForAll", "\x02200"),+    ("Fouriertrf", "\x02131"),+    ("Fscr", "\x02131"),+    ("GJcy", "\x00403"),+    ("GT", "\x0003E"),+    ("Gamma", "\x00393"),+    ("Gammad", "\x003DC"),+    ("Gbreve", "\x0011E"),+    ("Gcedil", "\x00122"),+    ("Gcirc", "\x0011C"),+    ("Gcy", "\x00413"),+    ("Gdot", "\x00120"),+    ("Gfr", "\x1D50A"),+    ("Gg", "\x022D9"),+    ("Gopf", "\x1D53E"),+    ("GreaterEqual", "\x02265"),+    ("GreaterEqualLess", "\x022DB"),+    ("GreaterFullEqual", "\x02267"),+    ("GreaterGreater", "\x02AA2"),+    ("GreaterLess", "\x02277"),+    ("GreaterSlantEqual", "\x02A7E"),+    ("GreaterTilde", "\x02273"),+    ("Gscr", "\x1D4A2"),+    ("Gt", "\x0226B"),+    ("HARDcy", "\x0042A"),+    ("Hacek", "\x002C7"),+    ("Hat", "\x0005E"),+    ("Hcirc", "\x00124"),+    ("Hfr", "\x0210C"),+    ("HilbertSpace", "\x0210B"),+    ("Hopf", "\x0210D"),+    ("HorizontalLine", "\x02500"),+    ("Hscr", "\x0210B"),+    ("Hstrok", "\x00126"),+    ("HumpDownHump", "\x0224E"),+    ("HumpEqual", "\x0224F") ]++reftab6 :: [(Text,Text)]+reftab6 =+  [ ("IEcy", "\x00415"),+    ("IJlig", "\x00132"),+    ("IOcy", "\x00401"),+    ("Iacute", "\x000CD"),+    ("Icirc", "\x000CE"),+    ("Icy", "\x00418"),+    ("Idot", "\x00130"),+    ("Ifr", "\x02111"),+    ("Igrave", "\x000CC"),+    ("Im", "\x02111"),+    ("Imacr", "\x0012A"),+    ("ImaginaryI", "\x02148"),+    ("Implies", "\x021D2"),+    ("Int", "\x0222C"),+    ("Integral", "\x0222B"),+    ("Intersection", "\x022C2"),+    ("InvisibleComma", "\x02063"),+    ("InvisibleTimes", "\x02062"),+    ("Iogon", "\x0012E"),+    ("Iopf", "\x1D540"),+    ("Iota", "\x00399"),+    ("Iscr", "\x02110"),+    ("Itilde", "\x00128"),+    ("Iukcy", "\x00406"),+    ("Iuml", "\x000CF"),+    ("Jcirc", "\x00134"),+    ("Jcy", "\x00419"),+    ("Jfr", "\x1D50D"),+    ("Jopf", "\x1D541"),+    ("Jscr", "\x1D4A5"),+    ("Jsercy", "\x00408"),+    ("Jukcy", "\x00404"),+    ("KHcy", "\x00425"),+    ("KJcy", "\x0040C"),+    ("Kappa", "\x0039A"),+    ("Kcedil", "\x00136"),+    ("Kcy", "\x0041A") ]++reftab7 :: [(Text,Text)]+reftab7 =+  [ ("Kfr", "\x1D50E"),+    ("Kopf", "\x1D542"),+    ("Kscr", "\x1D4A6"),+    ("LJcy", "\x00409"),+    ("LT", "\x0003C"),+    ("Lacute", "\x00139"),+    ("Lambda", "\x0039B"),+    ("Lang", "\x027EA"),+    ("Laplacetrf", "\x02112"),+    ("Larr", "\x0219E"),+    ("Lcaron", "\x0013D"),+    ("Lcedil", "\x0013B"),+    ("Lcy", "\x0041B"),+    ("LeftAngleBracket", "\x027E8"),+    ("LeftArrow", "\x02190"),+    ("LeftArrowBar", "\x021E4"),+    ("LeftArrowRightArrow", "\x021C6"),+    ("LeftCeiling", "\x02308"),+    ("LeftDoubleBracket", "\x027E6"),+    ("LeftDownTeeVector", "\x02961"),+    ("LeftDownVector", "\x021C3"),+    ("LeftDownVectorBar", "\x02959"),+    ("LeftFloor", "\x0230A"),+    ("LeftRightArrow", "\x02194"),+    ("LeftRightVector", "\x0294E"),+    ("LeftTee", "\x022A3"),+    ("LeftTeeArrow", "\x021A4"),+    ("LeftTeeVector", "\x0295A"),+    ("LeftTriangle", "\x022B2"),+    ("LeftTriangleBar", "\x029CF"),+    ("LeftTriangleEqual", "\x022B4"),+    ("LeftUpDownVector", "\x02951"),+    ("LeftUpTeeVector", "\x02960"),+    ("LeftUpVector", "\x021BF"),+    ("LeftUpVectorBar", "\x02958"),+    ("LeftVector", "\x021BC"),+    ("LeftVectorBar", "\x02952") ]++reftab8 :: [(Text,Text)]+reftab8 =+  [ ("Leftarrow", "\x021D0"),+    ("Leftrightarrow", "\x021D4"),+    ("LessEqualGreater", "\x022DA"),+    ("LessFullEqual", "\x02266"),+    ("LessGreater", "\x02276"),+    ("LessLess", "\x02AA1"),+    ("LessSlantEqual", "\x02A7D"),+    ("LessTilde", "\x02272"),+    ("Lfr", "\x1D50F"),+    ("Ll", "\x022D8"),+    ("Lleftarrow", "\x021DA"),+    ("Lmidot", "\x0013F"),+    ("LongLeftArrow", "\x027F5"),+    ("LongLeftRightArrow", "\x027F7"),+    ("LongRightArrow", "\x027F6"),+    ("Longleftarrow", "\x027F8"),+    ("Longleftrightarrow", "\x027FA"),+    ("Longrightarrow", "\x027F9"),+    ("Lopf", "\x1D543"),+    ("LowerLeftArrow", "\x02199"),+    ("LowerRightArrow", "\x02198"),+    ("Lscr", "\x02112"),+    ("Lsh", "\x021B0"),+    ("Lstrok", "\x00141"),+    ("Lt", "\x0226A"),+    ("Map", "\x02905"),+    ("Mcy", "\x0041C"),+    ("MediumSpace", "\x0205F"),+    ("Mellintrf", "\x02133"),+    ("Mfr", "\x1D510"),+    ("MinusPlus", "\x02213"),+    ("Mopf", "\x1D544"),+    ("Mscr", "\x02133"),+    ("Mu", "\x0039C"),+    ("NJcy", "\x0040A"),+    ("Nacute", "\x00143"),+    ("Ncaron", "\x00147") ]++reftab9 :: [(Text,Text)]+reftab9 =+  [ ("Ncedil", "\x00145"),+    ("Ncy", "\x0041D"),+    ("NegativeMediumSpace", "\x0200B"),+    ("NegativeThickSpace", "\x0200B"),+    ("NegativeThinSpace", "\x0200B"),+    ("NegativeVeryThinSpace", "\x0200B"),+    ("NestedGreaterGreater", "\x0226B"),+    ("NestedLessLess", "\x0226A"),+    ("NewLine", "\x0000A"),+    ("Nfr", "\x1D511"),+    ("NoBreak", "\x02060"),+    ("NonBreakingSpace", "\x000A0"),+    ("Nopf", "\x02115"),+    ("Not", "\x02AEC"),+    ("NotCongruent", "\x02262"),+    ("NotCupCap", "\x0226D"),+    ("NotDoubleVerticalBar", "\x02226"),+    ("NotElement", "\x02209"),+    ("NotEqual", "\x02260"),+    ("NotEqualTilde", "\x02242\x00338"),+    ("NotExists", "\x02204"),+    ("NotGreater", "\x0226F"),+    ("NotGreaterEqual", "\x02271"),+    ("NotGreaterFullEqual", "\x02267\x00338"),+    ("NotGreaterGreater", "\x0226B\x00338"),+    ("NotGreaterLess", "\x02279"),+    ("NotGreaterSlantEqual", "\x02A7E\x00338"),+    ("NotGreaterTilde", "\x02275"),+    ("NotHumpDownHump", "\x0224E\x00338"),+    ("NotHumpEqual", "\x0224F\x00338"),+    ("NotLeftTriangle", "\x022EA"),+    ("NotLeftTriangleBar", "\x029CF\x00338"),+    ("NotLeftTriangleEqual", "\x022EC"),+    ("NotLess", "\x0226E"),+    ("NotLessEqual", "\x02270"),+    ("NotLessGreater", "\x02278"),+    ("NotLessLess", "\x0226A\x00338") ]++reftab10 :: [(Text,Text)]+reftab10 =+  [ ("NotLessSlantEqual", "\x02A7D\x00338"),+    ("NotLessTilde", "\x02274"),+    ("NotNestedGreaterGreater", "\x02AA2\x00338"),+    ("NotNestedLessLess", "\x02AA1\x00338"),+    ("NotPrecedes", "\x02280"),+    ("NotPrecedesEqual", "\x02AAF\x00338"),+    ("NotPrecedesSlantEqual", "\x022E0"),+    ("NotReverseElement", "\x0220C"),+    ("NotRightTriangle", "\x022EB"),+    ("NotRightTriangleBar", "\x029D0\x00338"),+    ("NotRightTriangleEqual", "\x022ED"),+    ("NotSquareSubset", "\x0228F\x00338"),+    ("NotSquareSubsetEqual", "\x022E2"),+    ("NotSquareSuperset", "\x02290\x00338"),+    ("NotSquareSupersetEqual", "\x022E3"),+    ("NotSubset", "\x02282\x020D2"),+    ("NotSubsetEqual", "\x02288"),+    ("NotSucceeds", "\x02281"),+    ("NotSucceedsEqual", "\x02AB0\x00338"),+    ("NotSucceedsSlantEqual", "\x022E1"),+    ("NotSucceedsTilde", "\x0227F\x00338"),+    ("NotSuperset", "\x02283\x020D2"),+    ("NotSupersetEqual", "\x02289"),+    ("NotTilde", "\x02241"),+    ("NotTildeEqual", "\x02244"),+    ("NotTildeFullEqual", "\x02247"),+    ("NotTildeTilde", "\x02249"),+    ("NotVerticalBar", "\x02224"),+    ("Nscr", "\x1D4A9"),+    ("Ntilde", "\x000D1"),+    ("Nu", "\x0039D"),+    ("OElig", "\x00152"),+    ("Oacute", "\x000D3"),+    ("Ocirc", "\x000D4"),+    ("Ocy", "\x0041E"),+    ("Odblac", "\x00150"),+    ("Ofr", "\x1D512") ]++reftab11 :: [(Text,Text)]+reftab11 =+  [ ("Ograve", "\x000D2"),+    ("Omacr", "\x0014C"),+    ("Omega", "\x003A9"),+    ("Omicron", "\x0039F"),+    ("Oopf", "\x1D546"),+    ("OpenCurlyDoubleQuote", "\x0201C"),+    ("OpenCurlyQuote", "\x02018"),+    ("Or", "\x02A54"),+    ("Oscr", "\x1D4AA"),+    ("Oslash", "\x000D8"),+    ("Otilde", "\x000D5"),+    ("Otimes", "\x02A37"),+    ("Ouml", "\x000D6"),+    ("OverBar", "\x0203E"),+    ("OverBrace", "\x023DE"),+    ("OverBracket", "\x023B4"),+    ("OverParenthesis", "\x023DC"),+    ("PartialD", "\x02202"),+    ("Pcy", "\x0041F"),+    ("Pfr", "\x1D513"),+    ("Phi", "\x003A6"),+    ("Pi", "\x003A0"),+    ("PlusMinus", "\x000B1"),+    ("Poincareplane", "\x0210C"),+    ("Popf", "\x02119"),+    ("Pr", "\x02ABB"),+    ("Precedes", "\x0227A"),+    ("PrecedesEqual", "\x02AAF"),+    ("PrecedesSlantEqual", "\x0227C"),+    ("PrecedesTilde", "\x0227E"),+    ("Prime", "\x02033"),+    ("Product", "\x0220F"),+    ("Proportion", "\x02237"),+    ("Proportional", "\x0221D"),+    ("Pscr", "\x1D4AB"),+    ("Psi", "\x003A8"),+    ("QUOT", "\x00022") ]++reftab12 :: [(Text,Text)]+reftab12 =+  [ ("Qfr", "\x1D514"),+    ("Qopf", "\x0211A"),+    ("Qscr", "\x1D4AC"),+    ("RBarr", "\x02910"),+    ("REG", "\x000AE"),+    ("Racute", "\x00154"),+    ("Rang", "\x027EB"),+    ("Rarr", "\x021A0"),+    ("Rarrtl", "\x02916"),+    ("Rcaron", "\x00158"),+    ("Rcedil", "\x00156"),+    ("Rcy", "\x00420"),+    ("Re", "\x0211C"),+    ("ReverseElement", "\x0220B"),+    ("ReverseEquilibrium", "\x021CB"),+    ("ReverseUpEquilibrium", "\x0296F"),+    ("Rfr", "\x0211C"),+    ("Rho", "\x003A1"),+    ("RightAngleBracket", "\x027E9"),+    ("RightArrow", "\x02192"),+    ("RightArrowBar", "\x021E5"),+    ("RightArrowLeftArrow", "\x021C4"),+    ("RightCeiling", "\x02309"),+    ("RightDoubleBracket", "\x027E7"),+    ("RightDownTeeVector", "\x0295D"),+    ("RightDownVector", "\x021C2"),+    ("RightDownVectorBar", "\x02955"),+    ("RightFloor", "\x0230B"),+    ("RightTee", "\x022A2"),+    ("RightTeeArrow", "\x021A6"),+    ("RightTeeVector", "\x0295B"),+    ("RightTriangle", "\x022B3"),+    ("RightTriangleBar", "\x029D0"),+    ("RightTriangleEqual", "\x022B5"),+    ("RightUpDownVector", "\x0294F"),+    ("RightUpTeeVector", "\x0295C"),+    ("RightUpVector", "\x021BE") ]++reftab13 :: [(Text,Text)]+reftab13 =+  [ ("RightUpVectorBar", "\x02954"),+    ("RightVector", "\x021C0"),+    ("RightVectorBar", "\x02953"),+    ("Rightarrow", "\x021D2"),+    ("Ropf", "\x0211D"),+    ("RoundImplies", "\x02970"),+    ("Rrightarrow", "\x021DB"),+    ("Rscr", "\x0211B"),+    ("Rsh", "\x021B1"),+    ("RuleDelayed", "\x029F4"),+    ("SHCHcy", "\x00429"),+    ("SHcy", "\x00428"),+    ("SOFTcy", "\x0042C"),+    ("Sacute", "\x0015A"),+    ("Sc", "\x02ABC"),+    ("Scaron", "\x00160"),+    ("Scedil", "\x0015E"),+    ("Scirc", "\x0015C"),+    ("Scy", "\x00421"),+    ("Sfr", "\x1D516"),+    ("ShortDownArrow", "\x02193"),+    ("ShortLeftArrow", "\x02190"),+    ("ShortRightArrow", "\x02192"),+    ("ShortUpArrow", "\x02191"),+    ("Sigma", "\x003A3"),+    ("SmallCircle", "\x02218"),+    ("Sopf", "\x1D54A"),+    ("Sqrt", "\x0221A"),+    ("Square", "\x025A1"),+    ("SquareIntersection", "\x02293"),+    ("SquareSubset", "\x0228F"),+    ("SquareSubsetEqual", "\x02291"),+    ("SquareSuperset", "\x02290"),+    ("SquareSupersetEqual", "\x02292"),+    ("SquareUnion", "\x02294"),+    ("Sscr", "\x1D4AE"),+    ("Star", "\x022C6") ]++reftab14 :: [(Text,Text)]+reftab14 =+  [ ("Sub", "\x022D0"),+    ("Subset", "\x022D0"),+    ("SubsetEqual", "\x02286"),+    ("Succeeds", "\x0227B"),+    ("SucceedsEqual", "\x02AB0"),+    ("SucceedsSlantEqual", "\x0227D"),+    ("SucceedsTilde", "\x0227F"),+    ("SuchThat", "\x0220B"),+    ("Sum", "\x02211"),+    ("Sup", "\x022D1"),+    ("Superset", "\x02283"),+    ("SupersetEqual", "\x02287"),+    ("Supset", "\x022D1"),+    ("THORN", "\x000DE"),+    ("TRADE", "\x02122"),+    ("TSHcy", "\x0040B"),+    ("TScy", "\x00426"),+    ("Tab", "\x00009"),+    ("Tau", "\x003A4"),+    ("Tcaron", "\x00164"),+    ("Tcedil", "\x00162"),+    ("Tcy", "\x00422"),+    ("Tfr", "\x1D517"),+    ("Therefore", "\x02234"),+    ("Theta", "\x00398"),+    ("ThickSpace", "\x0205F\x0200A"),+    ("ThinSpace", "\x02009"),+    ("Tilde", "\x0223C"),+    ("TildeEqual", "\x02243"),+    ("TildeFullEqual", "\x02245"),+    ("TildeTilde", "\x02248"),+    ("Topf", "\x1D54B"),+    ("TripleDot", "\x020DB"),+    ("Tscr", "\x1D4AF"),+    ("Tstrok", "\x00166"),+    ("Uacute", "\x000DA"),+    ("Uarr", "\x0219F") ]++reftab15 :: [(Text,Text)]+reftab15 =+  [ ("Uarrocir", "\x02949"),+    ("Ubrcy", "\x0040E"),+    ("Ubreve", "\x0016C"),+    ("Ucirc", "\x000DB"),+    ("Ucy", "\x00423"),+    ("Udblac", "\x00170"),+    ("Ufr", "\x1D518"),+    ("Ugrave", "\x000D9"),+    ("Umacr", "\x0016A"),+    ("UnderBar", "\x0005F"),+    ("UnderBrace", "\x023DF"),+    ("UnderBracket", "\x023B5"),+    ("UnderParenthesis", "\x023DD"),+    ("Union", "\x022C3"),+    ("UnionPlus", "\x0228E"),+    ("Uogon", "\x00172"),+    ("Uopf", "\x1D54C"),+    ("UpArrow", "\x02191"),+    ("UpArrowBar", "\x02912"),+    ("UpArrowDownArrow", "\x021C5"),+    ("UpDownArrow", "\x02195"),+    ("UpEquilibrium", "\x0296E"),+    ("UpTee", "\x022A5"),+    ("UpTeeArrow", "\x021A5"),+    ("Uparrow", "\x021D1"),+    ("Updownarrow", "\x021D5"),+    ("UpperLeftArrow", "\x02196"),+    ("UpperRightArrow", "\x02197"),+    ("Upsi", "\x003D2"),+    ("Upsilon", "\x003A5"),+    ("Uring", "\x0016E"),+    ("Uscr", "\x1D4B0"),+    ("Utilde", "\x00168"),+    ("Uuml", "\x000DC"),+    ("VDash", "\x022AB"),+    ("Vbar", "\x02AEB"),+    ("Vcy", "\x00412") ]++reftab16 :: [(Text,Text)]+reftab16 =+  [ ("Vdash", "\x022A9"),+    ("Vdashl", "\x02AE6"),+    ("Vee", "\x022C1"),+    ("Verbar", "\x02016"),+    ("Vert", "\x02016"),+    ("VerticalBar", "\x02223"),+    ("VerticalLine", "\x0007C"),+    ("VerticalSeparator", "\x02758"),+    ("VerticalTilde", "\x02240"),+    ("VeryThinSpace", "\x0200A"),+    ("Vfr", "\x1D519"),+    ("Vopf", "\x1D54D"),+    ("Vscr", "\x1D4B1"),+    ("Vvdash", "\x022AA"),+    ("Wcirc", "\x00174"),+    ("Wedge", "\x022C0"),+    ("Wfr", "\x1D51A"),+    ("Wopf", "\x1D54E"),+    ("Wscr", "\x1D4B2"),+    ("Xfr", "\x1D51B"),+    ("Xi", "\x0039E"),+    ("Xopf", "\x1D54F"),+    ("Xscr", "\x1D4B3"),+    ("YAcy", "\x0042F"),+    ("YIcy", "\x00407"),+    ("YUcy", "\x0042E"),+    ("Yacute", "\x000DD"),+    ("Ycirc", "\x00176"),+    ("Ycy", "\x0042B"),+    ("Yfr", "\x1D51C"),+    ("Yopf", "\x1D550"),+    ("Yscr", "\x1D4B4"),+    ("Yuml", "\x00178"),+    ("ZHcy", "\x00416"),+    ("Zacute", "\x00179"),+    ("Zcaron", "\x0017D"),+    ("Zcy", "\x00417") ]++reftab17 :: [(Text,Text)]+reftab17 =+  [ ("Zdot", "\x0017B"),+    ("ZeroWidthSpace", "\x0200B"),+    ("Zeta", "\x00396"),+    ("Zfr", "\x02128"),+    ("Zopf", "\x02124"),+    ("Zscr", "\x1D4B5"),+    ("aacute", "\x000E1"),+    ("abreve", "\x00103"),+    ("ac", "\x0223E"),+    ("acE", "\x0223E\x00333"),+    ("acd", "\x0223F"),+    ("acirc", "\x000E2"),+    ("acute", "\x000B4"),+    ("acy", "\x00430"),+    ("aelig", "\x000E6"),+    ("af", "\x02061"),+    ("afr", "\x1D51E"),+    ("agrave", "\x000E0"),+    ("alefsym", "\x02135"),+    ("aleph", "\x02135"),+    ("alpha", "\x003B1"),+    ("amacr", "\x00101"),+    ("amalg", "\x02A3F"),+    ("amp", "\x00026"),+    ("and", "\x02227"),+    ("andand", "\x02A55"),+    ("andd", "\x02A5C"),+    ("andslope", "\x02A58"),+    ("andv", "\x02A5A"),+    ("ang", "\x02220"),+    ("ange", "\x029A4"),+    ("angle", "\x02220"),+    ("angmsd", "\x02221"),+    ("angmsdaa", "\x029A8"),+    ("angmsdab", "\x029A9"),+    ("angmsdac", "\x029AA"),+    ("angmsdad", "\x029AB") ]++reftab18 :: [(Text,Text)]+reftab18 =+  [ ("angmsdae", "\x029AC"),+    ("angmsdaf", "\x029AD"),+    ("angmsdag", "\x029AE"),+    ("angmsdah", "\x029AF"),+    ("angrt", "\x0221F"),+    ("angrtvb", "\x022BE"),+    ("angrtvbd", "\x0299D"),+    ("angsph", "\x02222"),+    ("angst", "\x000C5"),+    ("angzarr", "\x0237C"),+    ("aogon", "\x00105"),+    ("aopf", "\x1D552"),+    ("ap", "\x02248"),+    ("apE", "\x02A70"),+    ("apacir", "\x02A6F"),+    ("ape", "\x0224A"),+    ("apid", "\x0224B"),+    ("apos", "\x00027"),+    ("approx", "\x02248"),+    ("approxeq", "\x0224A"),+    ("aring", "\x000E5"),+    ("ascr", "\x1D4B6"),+    ("ast", "\x0002A"),+    ("asymp", "\x02248"),+    ("asympeq", "\x0224D"),+    ("atilde", "\x000E3"),+    ("auml", "\x000E4"),+    ("awconint", "\x02233"),+    ("awint", "\x02A11"),+    ("bNot", "\x02AED"),+    ("backcong", "\x0224C"),+    ("backepsilon", "\x003F6"),+    ("backprime", "\x02035"),+    ("backsim", "\x0223D"),+    ("backsimeq", "\x022CD"),+    ("barvee", "\x022BD"),+    ("barwed", "\x02305") ]++reftab19 :: [(Text,Text)]+reftab19 =+  [ ("barwedge", "\x02305"),+    ("bbrk", "\x023B5"),+    ("bbrktbrk", "\x023B6"),+    ("bcong", "\x0224C"),+    ("bcy", "\x00431"),+    ("bdquo", "\x0201E"),+    ("becaus", "\x02235"),+    ("because", "\x02235"),+    ("bemptyv", "\x029B0"),+    ("bepsi", "\x003F6"),+    ("bernou", "\x0212C"),+    ("beta", "\x003B2"),+    ("beth", "\x02136"),+    ("between", "\x0226C"),+    ("bfr", "\x1D51F"),+    ("bigcap", "\x022C2"),+    ("bigcirc", "\x025EF"),+    ("bigcup", "\x022C3"),+    ("bigodot", "\x02A00"),+    ("bigoplus", "\x02A01"),+    ("bigotimes", "\x02A02"),+    ("bigsqcup", "\x02A06"),+    ("bigstar", "\x02605"),+    ("bigtriangledown", "\x025BD"),+    ("bigtriangleup", "\x025B3"),+    ("biguplus", "\x02A04"),+    ("bigvee", "\x022C1"),+    ("bigwedge", "\x022C0"),+    ("bkarow", "\x0290D"),+    ("blacklozenge", "\x029EB"),+    ("blacksquare", "\x025AA"),+    ("blacktriangle", "\x025B4"),+    ("blacktriangledown", "\x025BE"),+    ("blacktriangleleft", "\x025C2"),+    ("blacktriangleright", "\x025B8"),+    ("blank", "\x02423"),+    ("blk12", "\x02592") ]++reftab20 :: [(Text,Text)]+reftab20 =+  [ ("blk14", "\x02591"),+    ("blk34", "\x02593"),+    ("block", "\x02588"),+    ("bne", "\x0003D\x020E5"),+    ("bnequiv", "\x02261\x020E5"),+    ("bnot", "\x02310"),+    ("bopf", "\x1D553"),+    ("bot", "\x022A5"),+    ("bottom", "\x022A5"),+    ("bowtie", "\x022C8"),+    ("boxDL", "\x02557"),+    ("boxDR", "\x02554"),+    ("boxDl", "\x02556"),+    ("boxDr", "\x02553"),+    ("boxH", "\x02550"),+    ("boxHD", "\x02566"),+    ("boxHU", "\x02569"),+    ("boxHd", "\x02564"),+    ("boxHu", "\x02567"),+    ("boxUL", "\x0255D"),+    ("boxUR", "\x0255A"),+    ("boxUl", "\x0255C"),+    ("boxUr", "\x02559"),+    ("boxV", "\x02551"),+    ("boxVH", "\x0256C"),+    ("boxVL", "\x02563"),+    ("boxVR", "\x02560"),+    ("boxVh", "\x0256B"),+    ("boxVl", "\x02562"),+    ("boxVr", "\x0255F"),+    ("boxbox", "\x029C9"),+    ("boxdL", "\x02555"),+    ("boxdR", "\x02552"),+    ("boxdl", "\x02510"),+    ("boxdr", "\x0250C"),+    ("boxh", "\x02500"),+    ("boxhD", "\x02565") ]++reftab21 :: [(Text,Text)]+reftab21 =+  [ ("boxhU", "\x02568"),+    ("boxhd", "\x0252C"),+    ("boxhu", "\x02534"),+    ("boxminus", "\x0229F"),+    ("boxplus", "\x0229E"),+    ("boxtimes", "\x022A0"),+    ("boxuL", "\x0255B"),+    ("boxuR", "\x02558"),+    ("boxul", "\x02518"),+    ("boxur", "\x02514"),+    ("boxv", "\x02502"),+    ("boxvH", "\x0256A"),+    ("boxvL", "\x02561"),+    ("boxvR", "\x0255E"),+    ("boxvh", "\x0253C"),+    ("boxvl", "\x02524"),+    ("boxvr", "\x0251C"),+    ("bprime", "\x02035"),+    ("breve", "\x002D8"),+    ("brvbar", "\x000A6"),+    ("bscr", "\x1D4B7"),+    ("bsemi", "\x0204F"),+    ("bsim", "\x0223D"),+    ("bsime", "\x022CD"),+    ("bsol", "\x0005C"),+    ("bsolb", "\x029C5"),+    ("bsolhsub", "\x027C8"),+    ("bull", "\x02022"),+    ("bullet", "\x02022"),+    ("bump", "\x0224E"),+    ("bumpE", "\x02AAE"),+    ("bumpe", "\x0224F"),+    ("bumpeq", "\x0224F"),+    ("cacute", "\x00107"),+    ("cap", "\x02229"),+    ("capand", "\x02A44"),+    ("capbrcup", "\x02A49") ]++reftab22 :: [(Text,Text)]+reftab22 =+  [ ("capcap", "\x02A4B"),+    ("capcup", "\x02A47"),+    ("capdot", "\x02A40"),+    ("caps", "\x02229\x0FE00"),+    ("caret", "\x02041"),+    ("caron", "\x002C7"),+    ("ccaps", "\x02A4D"),+    ("ccaron", "\x0010D"),+    ("ccedil", "\x000E7"),+    ("ccirc", "\x00109"),+    ("ccups", "\x02A4C"),+    ("ccupssm", "\x02A50"),+    ("cdot", "\x0010B"),+    ("cedil", "\x000B8"),+    ("cemptyv", "\x029B2"),+    ("cent", "\x000A2"),+    ("centerdot", "\x000B7"),+    ("cfr", "\x1D520"),+    ("chcy", "\x00447"),+    ("check", "\x02713"),+    ("checkmark", "\x02713"),+    ("chi", "\x003C7"),+    ("cir", "\x025CB"),+    ("cirE", "\x029C3"),+    ("circ", "\x002C6"),+    ("circeq", "\x02257"),+    ("circlearrowleft", "\x021BA"),+    ("circlearrowright", "\x021BB"),+    ("circledR", "\x000AE"),+    ("circledS", "\x024C8"),+    ("circledast", "\x0229B"),+    ("circledcirc", "\x0229A"),+    ("circleddash", "\x0229D"),+    ("cire", "\x02257"),+    ("cirfnint", "\x02A10"),+    ("cirmid", "\x02AEF"),+    ("cirscir", "\x029C2") ]++reftab23 :: [(Text,Text)]+reftab23 =+  [ ("clubs", "\x02663"),+    ("clubsuit", "\x02663"),+    ("colon", "\x0003A"),+    ("colone", "\x02254"),+    ("coloneq", "\x02254"),+    ("comma", "\x0002C"),+    ("commat", "\x00040"),+    ("comp", "\x02201"),+    ("compfn", "\x02218"),+    ("complement", "\x02201"),+    ("complexes", "\x02102"),+    ("cong", "\x02245"),+    ("congdot", "\x02A6D"),+    ("conint", "\x0222E"),+    ("copf", "\x1D554"),+    ("coprod", "\x02210"),+    ("copy", "\x000A9"),+    ("copysr", "\x02117"),+    ("crarr", "\x021B5"),+    ("cross", "\x02717"),+    ("cscr", "\x1D4B8"),+    ("csub", "\x02ACF"),+    ("csube", "\x02AD1"),+    ("csup", "\x02AD0"),+    ("csupe", "\x02AD2"),+    ("ctdot", "\x022EF"),+    ("cudarrl", "\x02938"),+    ("cudarrr", "\x02935"),+    ("cuepr", "\x022DE"),+    ("cuesc", "\x022DF"),+    ("cularr", "\x021B6"),+    ("cularrp", "\x0293D"),+    ("cup", "\x0222A"),+    ("cupbrcap", "\x02A48"),+    ("cupcap", "\x02A46"),+    ("cupcup", "\x02A4A"),+    ("cupdot", "\x0228D") ]++reftab24 :: [(Text,Text)]+reftab24 =+  [ ("cupor", "\x02A45"),+    ("cups", "\x0222A\x0FE00"),+    ("curarr", "\x021B7"),+    ("curarrm", "\x0293C"),+    ("curlyeqprec", "\x022DE"),+    ("curlyeqsucc", "\x022DF"),+    ("curlyvee", "\x022CE"),+    ("curlywedge", "\x022CF"),+    ("curren", "\x000A4"),+    ("curvearrowleft", "\x021B6"),+    ("curvearrowright", "\x021B7"),+    ("cuvee", "\x022CE"),+    ("cuwed", "\x022CF"),+    ("cwconint", "\x02232"),+    ("cwint", "\x02231"),+    ("cylcty", "\x0232D"),+    ("dArr", "\x021D3"),+    ("dHar", "\x02965"),+    ("dagger", "\x02020"),+    ("daleth", "\x02138"),+    ("darr", "\x02193"),+    ("dash", "\x02010"),+    ("dashv", "\x022A3"),+    ("dbkarow", "\x0290F"),+    ("dblac", "\x002DD"),+    ("dcaron", "\x0010F"),+    ("dcy", "\x00434"),+    ("dd", "\x02146"),+    ("ddagger", "\x02021"),+    ("ddarr", "\x021CA"),+    ("ddotseq", "\x02A77"),+    ("deg", "\x000B0"),+    ("delta", "\x003B4"),+    ("demptyv", "\x029B1"),+    ("dfisht", "\x0297F"),+    ("dfr", "\x1D521"),+    ("dharl", "\x021C3") ]++reftab25 :: [(Text,Text)]+reftab25 =+  [ ("dharr", "\x021C2"),+    ("diam", "\x022C4"),+    ("diamond", "\x022C4"),+    ("diamondsuit", "\x02666"),+    ("diams", "\x02666"),+    ("die", "\x000A8"),+    ("digamma", "\x003DD"),+    ("disin", "\x022F2"),+    ("div", "\x000F7"),+    ("divide", "\x000F7"),+    ("divideontimes", "\x022C7"),+    ("divonx", "\x022C7"),+    ("djcy", "\x00452"),+    ("dlcorn", "\x0231E"),+    ("dlcrop", "\x0230D"),+    ("dollar", "\x00024"),+    ("dopf", "\x1D555"),+    ("dot", "\x002D9"),+    ("doteq", "\x02250"),+    ("doteqdot", "\x02251"),+    ("dotminus", "\x02238"),+    ("dotplus", "\x02214"),+    ("dotsquare", "\x022A1"),+    ("doublebarwedge", "\x02306"),+    ("downarrow", "\x02193"),+    ("downdownarrows", "\x021CA"),+    ("downharpoonleft", "\x021C3"),+    ("downharpoonright", "\x021C2"),+    ("drbkarow", "\x02910"),+    ("drcorn", "\x0231F"),+    ("drcrop", "\x0230C"),+    ("dscr", "\x1D4B9"),+    ("dscy", "\x00455"),+    ("dsol", "\x029F6"),+    ("dstrok", "\x00111"),+    ("dtdot", "\x022F1"),+    ("dtri", "\x025BF") ]++reftab26 :: [(Text,Text)]+reftab26 =+  [ ("dtrif", "\x025BE"),+    ("duarr", "\x021F5"),+    ("duhar", "\x0296F"),+    ("dwangle", "\x029A6"),+    ("dzcy", "\x0045F"),+    ("dzigrarr", "\x027FF"),+    ("eDDot", "\x02A77"),+    ("eDot", "\x02251"),+    ("eacute", "\x000E9"),+    ("easter", "\x02A6E"),+    ("ecaron", "\x0011B"),+    ("ecir", "\x02256"),+    ("ecirc", "\x000EA"),+    ("ecolon", "\x02255"),+    ("ecy", "\x0044D"),+    ("edot", "\x00117"),+    ("ee", "\x02147"),+    ("efDot", "\x02252"),+    ("efr", "\x1D522"),+    ("eg", "\x02A9A"),+    ("egrave", "\x000E8"),+    ("egs", "\x02A96"),+    ("egsdot", "\x02A98"),+    ("el", "\x02A99"),+    ("elinters", "\x023E7"),+    ("ell", "\x02113"),+    ("els", "\x02A95"),+    ("elsdot", "\x02A97"),+    ("emacr", "\x00113"),+    ("empty", "\x02205"),+    ("emptyset", "\x02205"),+    ("emptyv", "\x02205"),+    ("emsp", "\x02003"),+    ("emsp13", "\x02004"),+    ("emsp14", "\x02005"),+    ("eng", "\x0014B"),+    ("ensp", "\x02002") ]++reftab27 :: [(Text,Text)]+reftab27 =+  [ ("eogon", "\x00119"),+    ("eopf", "\x1D556"),+    ("epar", "\x022D5"),+    ("eparsl", "\x029E3"),+    ("eplus", "\x02A71"),+    ("epsi", "\x003B5"),+    ("epsilon", "\x003B5"),+    ("epsiv", "\x003F5"),+    ("eqcirc", "\x02256"),+    ("eqcolon", "\x02255"),+    ("eqsim", "\x02242"),+    ("eqslantgtr", "\x02A96"),+    ("eqslantless", "\x02A95"),+    ("equals", "\x0003D"),+    ("equest", "\x0225F"),+    ("equiv", "\x02261"),+    ("equivDD", "\x02A78"),+    ("eqvparsl", "\x029E5"),+    ("erDot", "\x02253"),+    ("erarr", "\x02971"),+    ("escr", "\x0212F"),+    ("esdot", "\x02250"),+    ("esim", "\x02242"),+    ("eta", "\x003B7"),+    ("eth", "\x000F0"),+    ("euml", "\x000EB"),+    ("euro", "\x020AC"),+    ("excl", "\x00021"),+    ("exist", "\x02203"),+    ("expectation", "\x02130"),+    ("exponentiale", "\x02147"),+    ("fallingdotseq", "\x02252"),+    ("fcy", "\x00444"),+    ("female", "\x02640"),+    ("ffilig", "\x0FB03"),+    ("fflig", "\x0FB00"),+    ("ffllig", "\x0FB04") ]++reftab28 :: [(Text,Text)]+reftab28 =+  [ ("ffr", "\x1D523"),+    ("filig", "\x0FB01"),+    ("fjlig", "\x00066\x0006A"),+    ("flat", "\x0266D"),+    ("fllig", "\x0FB02"),+    ("fltns", "\x025B1"),+    ("fnof", "\x00192"),+    ("fopf", "\x1D557"),+    ("forall", "\x02200"),+    ("fork", "\x022D4"),+    ("forkv", "\x02AD9"),+    ("fpartint", "\x02A0D"),+    ("frac12", "\x000BD"),+    ("frac13", "\x02153"),+    ("frac14", "\x000BC"),+    ("frac15", "\x02155"),+    ("frac16", "\x02159"),+    ("frac18", "\x0215B"),+    ("frac23", "\x02154"),+    ("frac25", "\x02156"),+    ("frac34", "\x000BE"),+    ("frac35", "\x02157"),+    ("frac38", "\x0215C"),+    ("frac45", "\x02158"),+    ("frac56", "\x0215A"),+    ("frac58", "\x0215D"),+    ("frac78", "\x0215E"),+    ("frasl", "\x02044"),+    ("frown", "\x02322"),+    ("fscr", "\x1D4BB"),+    ("gE", "\x02267"),+    ("gEl", "\x02A8C"),+    ("gacute", "\x001F5"),+    ("gamma", "\x003B3"),+    ("gammad", "\x003DD"),+    ("gap", "\x02A86"),+    ("gbreve", "\x0011F") ]++reftab29 :: [(Text,Text)]+reftab29 =+  [ ("gcirc", "\x0011D"),+    ("gcy", "\x00433"),+    ("gdot", "\x00121"),+    ("ge", "\x02265"),+    ("gel", "\x022DB"),+    ("geq", "\x02265"),+    ("geqq", "\x02267"),+    ("geqslant", "\x02A7E"),+    ("ges", "\x02A7E"),+    ("gescc", "\x02AA9"),+    ("gesdot", "\x02A80"),+    ("gesdoto", "\x02A82"),+    ("gesdotol", "\x02A84"),+    ("gesl", "\x022DB\x0FE00"),+    ("gesles", "\x02A94"),+    ("gfr", "\x1D524"),+    ("gg", "\x0226B"),+    ("ggg", "\x022D9"),+    ("gimel", "\x02137"),+    ("gjcy", "\x00453"),+    ("gl", "\x02277"),+    ("glE", "\x02A92"),+    ("gla", "\x02AA5"),+    ("glj", "\x02AA4"),+    ("gnE", "\x02269"),+    ("gnap", "\x02A8A"),+    ("gnapprox", "\x02A8A"),+    ("gne", "\x02A88"),+    ("gneq", "\x02A88"),+    ("gneqq", "\x02269"),+    ("gnsim", "\x022E7"),+    ("gopf", "\x1D558"),+    ("grave", "\x00060"),+    ("gscr", "\x0210A"),+    ("gsim", "\x02273"),+    ("gsime", "\x02A8E"),+    ("gsiml", "\x02A90") ]++reftab30 :: [(Text,Text)]+reftab30 =+  [ ("gt", "\x0003E"),+    ("gtcc", "\x02AA7"),+    ("gtcir", "\x02A7A"),+    ("gtdot", "\x022D7"),+    ("gtlPar", "\x02995"),+    ("gtquest", "\x02A7C"),+    ("gtrapprox", "\x02A86"),+    ("gtrarr", "\x02978"),+    ("gtrdot", "\x022D7"),+    ("gtreqless", "\x022DB"),+    ("gtreqqless", "\x02A8C"),+    ("gtrless", "\x02277"),+    ("gtrsim", "\x02273"),+    ("gvertneqq", "\x02269\x0FE00"),+    ("gvnE", "\x02269\x0FE00"),+    ("hArr", "\x021D4"),+    ("hairsp", "\x0200A"),+    ("half", "\x000BD"),+    ("hamilt", "\x0210B"),+    ("hardcy", "\x0044A"),+    ("harr", "\x02194"),+    ("harrcir", "\x02948"),+    ("harrw", "\x021AD"),+    ("hbar", "\x0210F"),+    ("hcirc", "\x00125"),+    ("hearts", "\x02665"),+    ("heartsuit", "\x02665"),+    ("hellip", "\x02026"),+    ("hercon", "\x022B9"),+    ("hfr", "\x1D525"),+    ("hksearow", "\x02925"),+    ("hkswarow", "\x02926"),+    ("hoarr", "\x021FF"),+    ("homtht", "\x0223B"),+    ("hookleftarrow", "\x021A9"),+    ("hookrightarrow", "\x021AA"),+    ("hopf", "\x1D559") ]++reftab31 :: [(Text,Text)]+reftab31 =+  [ ("horbar", "\x02015"),+    ("hscr", "\x1D4BD"),+    ("hslash", "\x0210F"),+    ("hstrok", "\x00127"),+    ("hybull", "\x02043"),+    ("hyphen", "\x02010"),+    ("iacute", "\x000ED"),+    ("ic", "\x02063"),+    ("icirc", "\x000EE"),+    ("icy", "\x00438"),+    ("iecy", "\x00435"),+    ("iexcl", "\x000A1"),+    ("iff", "\x021D4"),+    ("ifr", "\x1D526"),+    ("igrave", "\x000EC"),+    ("ii", "\x02148"),+    ("iiiint", "\x02A0C"),+    ("iiint", "\x0222D"),+    ("iinfin", "\x029DC"),+    ("iiota", "\x02129"),+    ("ijlig", "\x00133"),+    ("imacr", "\x0012B"),+    ("image", "\x02111"),+    ("imagline", "\x02110"),+    ("imagpart", "\x02111"),+    ("imath", "\x00131"),+    ("imof", "\x022B7"),+    ("imped", "\x001B5"),+    ("in", "\x02208"),+    ("incare", "\x02105"),+    ("infin", "\x0221E"),+    ("infintie", "\x029DD"),+    ("inodot", "\x00131"),+    ("int", "\x0222B"),+    ("intcal", "\x022BA"),+    ("integers", "\x02124"),+    ("intercal", "\x022BA") ]++reftab32 :: [(Text,Text)]+reftab32 =+  [ ("intlarhk", "\x02A17"),+    ("intprod", "\x02A3C"),+    ("iocy", "\x00451"),+    ("iogon", "\x0012F"),+    ("iopf", "\x1D55A"),+    ("iota", "\x003B9"),+    ("iprod", "\x02A3C"),+    ("iquest", "\x000BF"),+    ("iscr", "\x1D4BE"),+    ("isin", "\x02208"),+    ("isinE", "\x022F9"),+    ("isindot", "\x022F5"),+    ("isins", "\x022F4"),+    ("isinsv", "\x022F3"),+    ("isinv", "\x02208"),+    ("it", "\x02062"),+    ("itilde", "\x00129"),+    ("iukcy", "\x00456"),+    ("iuml", "\x000EF"),+    ("jcirc", "\x00135"),+    ("jcy", "\x00439"),+    ("jfr", "\x1D527"),+    ("jmath", "\x00237"),+    ("jopf", "\x1D55B"),+    ("jscr", "\x1D4BF"),+    ("jsercy", "\x00458"),+    ("jukcy", "\x00454"),+    ("kappa", "\x003BA"),+    ("kappav", "\x003F0"),+    ("kcedil", "\x00137"),+    ("kcy", "\x0043A"),+    ("kfr", "\x1D528"),+    ("kgreen", "\x00138"),+    ("khcy", "\x00445"),+    ("kjcy", "\x0045C"),+    ("kopf", "\x1D55C"),+    ("kscr", "\x1D4C0") ]++reftab33 :: [(Text,Text)]+reftab33 =+  [ ("lAarr", "\x021DA"),+    ("lArr", "\x021D0"),+    ("lAtail", "\x0291B"),+    ("lBarr", "\x0290E"),+    ("lE", "\x02266"),+    ("lEg", "\x02A8B"),+    ("lHar", "\x02962"),+    ("lacute", "\x0013A"),+    ("laemptyv", "\x029B4"),+    ("lagran", "\x02112"),+    ("lambda", "\x003BB"),+    ("lang", "\x027E8"),+    ("langd", "\x02991"),+    ("langle", "\x027E8"),+    ("lap", "\x02A85"),+    ("laquo", "\x000AB"),+    ("larr", "\x02190"),+    ("larrb", "\x021E4"),+    ("larrbfs", "\x0291F"),+    ("larrfs", "\x0291D"),+    ("larrhk", "\x021A9"),+    ("larrlp", "\x021AB"),+    ("larrpl", "\x02939"),+    ("larrsim", "\x02973"),+    ("larrtl", "\x021A2"),+    ("lat", "\x02AAB"),+    ("latail", "\x02919"),+    ("late", "\x02AAD"),+    ("lates", "\x02AAD\x0FE00"),+    ("lbarr", "\x0290C"),+    ("lbbrk", "\x02772"),+    ("lbrace", "\x0007B"),+    ("lbrack", "\x0005B"),+    ("lbrke", "\x0298B"),+    ("lbrksld", "\x0298F"),+    ("lbrkslu", "\x0298D"),+    ("lcaron", "\x0013E") ]++reftab34 :: [(Text,Text)]+reftab34 =+  [ ("lcedil", "\x0013C"),+    ("lceil", "\x02308"),+    ("lcub", "\x0007B"),+    ("lcy", "\x0043B"),+    ("ldca", "\x02936"),+    ("ldquo", "\x0201C"),+    ("ldquor", "\x0201E"),+    ("ldrdhar", "\x02967"),+    ("ldrushar", "\x0294B"),+    ("ldsh", "\x021B2"),+    ("le", "\x02264"),+    ("leftarrow", "\x02190"),+    ("leftarrowtail", "\x021A2"),+    ("leftharpoondown", "\x021BD"),+    ("leftharpoonup", "\x021BC"),+    ("leftleftarrows", "\x021C7"),+    ("leftrightarrow", "\x02194"),+    ("leftrightarrows", "\x021C6"),+    ("leftrightharpoons", "\x021CB"),+    ("leftrightsquigarrow", "\x021AD"),+    ("leftthreetimes", "\x022CB"),+    ("leg", "\x022DA"),+    ("leq", "\x02264"),+    ("leqq", "\x02266"),+    ("leqslant", "\x02A7D"),+    ("les", "\x02A7D"),+    ("lescc", "\x02AA8"),+    ("lesdot", "\x02A7F"),+    ("lesdoto", "\x02A81"),+    ("lesdotor", "\x02A83"),+    ("lesg", "\x022DA\x0FE00"),+    ("lesges", "\x02A93"),+    ("lessapprox", "\x02A85"),+    ("lessdot", "\x022D6"),+    ("lesseqgtr", "\x022DA"),+    ("lesseqqgtr", "\x02A8B"),+    ("lessgtr", "\x02276") ]++reftab35 :: [(Text,Text)]+reftab35 =+  [ ("lesssim", "\x02272"),+    ("lfisht", "\x0297C"),+    ("lfloor", "\x0230A"),+    ("lfr", "\x1D529"),+    ("lg", "\x02276"),+    ("lgE", "\x02A91"),+    ("lhard", "\x021BD"),+    ("lharu", "\x021BC"),+    ("lharul", "\x0296A"),+    ("lhblk", "\x02584"),+    ("ljcy", "\x00459"),+    ("ll", "\x0226A"),+    ("llarr", "\x021C7"),+    ("llcorner", "\x0231E"),+    ("llhard", "\x0296B"),+    ("lltri", "\x025FA"),+    ("lmidot", "\x00140"),+    ("lmoust", "\x023B0"),+    ("lmoustache", "\x023B0"),+    ("lnE", "\x02268"),+    ("lnap", "\x02A89"),+    ("lnapprox", "\x02A89"),+    ("lne", "\x02A87"),+    ("lneq", "\x02A87"),+    ("lneqq", "\x02268"),+    ("lnsim", "\x022E6"),+    ("loang", "\x027EC"),+    ("loarr", "\x021FD"),+    ("lobrk", "\x027E6"),+    ("longleftarrow", "\x027F5"),+    ("longleftrightarrow", "\x027F7"),+    ("longmapsto", "\x027FC"),+    ("longrightarrow", "\x027F6"),+    ("looparrowleft", "\x021AB"),+    ("looparrowright", "\x021AC"),+    ("lopar", "\x02985"),+    ("lopf", "\x1D55D") ]++reftab36 :: [(Text,Text)]+reftab36 =+  [ ("loplus", "\x02A2D"),+    ("lotimes", "\x02A34"),+    ("lowast", "\x02217"),+    ("lowbar", "\x0005F"),+    ("loz", "\x025CA"),+    ("lozenge", "\x025CA"),+    ("lozf", "\x029EB"),+    ("lpar", "\x00028"),+    ("lparlt", "\x02993"),+    ("lrarr", "\x021C6"),+    ("lrcorner", "\x0231F"),+    ("lrhar", "\x021CB"),+    ("lrhard", "\x0296D"),+    ("lrm", "\x0200E"),+    ("lrtri", "\x022BF"),+    ("lsaquo", "\x02039"),+    ("lscr", "\x1D4C1"),+    ("lsh", "\x021B0"),+    ("lsim", "\x02272"),+    ("lsime", "\x02A8D"),+    ("lsimg", "\x02A8F"),+    ("lsqb", "\x0005B"),+    ("lsquo", "\x02018"),+    ("lsquor", "\x0201A"),+    ("lstrok", "\x00142"),+    ("lt", "\x0003C"),+    ("ltcc", "\x02AA6"),+    ("ltcir", "\x02A79"),+    ("ltdot", "\x022D6"),+    ("lthree", "\x022CB"),+    ("ltimes", "\x022C9"),+    ("ltlarr", "\x02976"),+    ("ltquest", "\x02A7B"),+    ("ltrPar", "\x02996"),+    ("ltri", "\x025C3"),+    ("ltrie", "\x022B4"),+    ("ltrif", "\x025C2") ]++reftab37 :: [(Text,Text)]+reftab37 =+  [ ("lurdshar", "\x0294A"),+    ("luruhar", "\x02966"),+    ("lvertneqq", "\x02268\x0FE00"),+    ("lvnE", "\x02268\x0FE00"),+    ("mDDot", "\x0223A"),+    ("macr", "\x000AF"),+    ("male", "\x02642"),+    ("malt", "\x02720"),+    ("maltese", "\x02720"),+    ("map", "\x021A6"),+    ("mapsto", "\x021A6"),+    ("mapstodown", "\x021A7"),+    ("mapstoleft", "\x021A4"),+    ("mapstoup", "\x021A5"),+    ("marker", "\x025AE"),+    ("mcomma", "\x02A29"),+    ("mcy", "\x0043C"),+    ("mdash", "\x02014"),+    ("measuredangle", "\x02221"),+    ("mfr", "\x1D52A"),+    ("mho", "\x02127"),+    ("micro", "\x000B5"),+    ("mid", "\x02223"),+    ("midast", "\x0002A"),+    ("midcir", "\x02AF0"),+    ("middot", "\x000B7"),+    ("minus", "\x02212"),+    ("minusb", "\x0229F"),+    ("minusd", "\x02238"),+    ("minusdu", "\x02A2A"),+    ("mlcp", "\x02ADB"),+    ("mldr", "\x02026"),+    ("mnplus", "\x02213"),+    ("models", "\x022A7"),+    ("mopf", "\x1D55E"),+    ("mp", "\x02213"),+    ("mscr", "\x1D4C2") ]++reftab38 :: [(Text,Text)]+reftab38 =+  [ ("mstpos", "\x0223E"),+    ("mu", "\x003BC"),+    ("multimap", "\x022B8"),+    ("mumap", "\x022B8"),+    ("nGg", "\x022D9\x00338"),+    ("nGt", "\x0226B\x020D2"),+    ("nGtv", "\x0226B\x00338"),+    ("nLeftarrow", "\x021CD"),+    ("nLeftrightarrow", "\x021CE"),+    ("nLl", "\x022D8\x00338"),+    ("nLt", "\x0226A\x020D2"),+    ("nLtv", "\x0226A\x00338"),+    ("nRightarrow", "\x021CF"),+    ("nVDash", "\x022AF"),+    ("nVdash", "\x022AE"),+    ("nabla", "\x02207"),+    ("nacute", "\x00144"),+    ("nang", "\x02220\x020D2"),+    ("nap", "\x02249"),+    ("napE", "\x02A70\x00338"),+    ("napid", "\x0224B\x00338"),+    ("napos", "\x00149"),+    ("napprox", "\x02249"),+    ("natur", "\x0266E"),+    ("natural", "\x0266E"),+    ("naturals", "\x02115"),+    ("nbsp", "\x000A0"),+    ("nbump", "\x0224E\x00338"),+    ("nbumpe", "\x0224F\x00338"),+    ("ncap", "\x02A43"),+    ("ncaron", "\x00148"),+    ("ncedil", "\x00146"),+    ("ncong", "\x02247"),+    ("ncongdot", "\x02A6D\x00338"),+    ("ncup", "\x02A42"),+    ("ncy", "\x0043D"),+    ("ndash", "\x02013") ]++reftab39 :: [(Text,Text)]+reftab39 =+  [ ("ne", "\x02260"),+    ("neArr", "\x021D7"),+    ("nearhk", "\x02924"),+    ("nearr", "\x02197"),+    ("nearrow", "\x02197"),+    ("nedot", "\x02250\x00338"),+    ("nequiv", "\x02262"),+    ("nesear", "\x02928"),+    ("nesim", "\x02242\x00338"),+    ("nexist", "\x02204"),+    ("nexists", "\x02204"),+    ("nfr", "\x1D52B"),+    ("ngE", "\x02267\x00338"),+    ("nge", "\x02271"),+    ("ngeq", "\x02271"),+    ("ngeqq", "\x02267\x00338"),+    ("ngeqslant", "\x02A7E\x00338"),+    ("nges", "\x02A7E\x00338"),+    ("ngsim", "\x02275"),+    ("ngt", "\x0226F"),+    ("ngtr", "\x0226F"),+    ("nhArr", "\x021CE"),+    ("nharr", "\x021AE"),+    ("nhpar", "\x02AF2"),+    ("ni", "\x0220B"),+    ("nis", "\x022FC"),+    ("nisd", "\x022FA"),+    ("niv", "\x0220B"),+    ("njcy", "\x0045A"),+    ("nlArr", "\x021CD"),+    ("nlE", "\x02266\x00338"),+    ("nlarr", "\x0219A"),+    ("nldr", "\x02025"),+    ("nle", "\x02270"),+    ("nleftarrow", "\x0219A"),+    ("nleftrightarrow", "\x021AE"),+    ("nleq", "\x02270") ]++reftab40 :: [(Text,Text)]+reftab40 =+  [ ("nleqq", "\x02266\x00338"),+    ("nleqslant", "\x02A7D\x00338"),+    ("nles", "\x02A7D\x00338"),+    ("nless", "\x0226E"),+    ("nlsim", "\x02274"),+    ("nlt", "\x0226E"),+    ("nltri", "\x022EA"),+    ("nltrie", "\x022EC"),+    ("nmid", "\x02224"),+    ("nopf", "\x1D55F"),+    ("not", "\x000AC"),+    ("notin", "\x02209"),+    ("notinE", "\x022F9\x00338"),+    ("notindot", "\x022F5\x00338"),+    ("notinva", "\x02209"),+    ("notinvb", "\x022F7"),+    ("notinvc", "\x022F6"),+    ("notni", "\x0220C"),+    ("notniva", "\x0220C"),+    ("notnivb", "\x022FE"),+    ("notnivc", "\x022FD"),+    ("npar", "\x02226"),+    ("nparallel", "\x02226"),+    ("nparsl", "\x02AFD\x020E5"),+    ("npart", "\x02202\x00338"),+    ("npolint", "\x02A14"),+    ("npr", "\x02280"),+    ("nprcue", "\x022E0"),+    ("npre", "\x02AAF\x00338"),+    ("nprec", "\x02280"),+    ("npreceq", "\x02AAF\x00338"),+    ("nrArr", "\x021CF"),+    ("nrarr", "\x0219B"),+    ("nrarrc", "\x02933\x00338"),+    ("nrarrw", "\x0219D\x00338"),+    ("nrightarrow", "\x0219B"),+    ("nrtri", "\x022EB") ]++reftab41 :: [(Text,Text)]+reftab41 =+  [ ("nrtrie", "\x022ED"),+    ("nsc", "\x02281"),+    ("nsccue", "\x022E1"),+    ("nsce", "\x02AB0\x00338"),+    ("nscr", "\x1D4C3"),+    ("nshortmid", "\x02224"),+    ("nshortparallel", "\x02226"),+    ("nsim", "\x02241"),+    ("nsime", "\x02244"),+    ("nsimeq", "\x02244"),+    ("nsmid", "\x02224"),+    ("nspar", "\x02226"),+    ("nsqsube", "\x022E2"),+    ("nsqsupe", "\x022E3"),+    ("nsub", "\x02284"),+    ("nsubE", "\x02AC5\x00338"),+    ("nsube", "\x02288"),+    ("nsubset", "\x02282\x020D2"),+    ("nsubseteq", "\x02288"),+    ("nsubseteqq", "\x02AC5\x00338"),+    ("nsucc", "\x02281"),+    ("nsucceq", "\x02AB0\x00338"),+    ("nsup", "\x02285"),+    ("nsupE", "\x02AC6\x00338"),+    ("nsupe", "\x02289"),+    ("nsupset", "\x02283\x020D2"),+    ("nsupseteq", "\x02289"),+    ("nsupseteqq", "\x02AC6\x00338"),+    ("ntgl", "\x02279"),+    ("ntilde", "\x000F1"),+    ("ntlg", "\x02278"),+    ("ntriangleleft", "\x022EA"),+    ("ntrianglelefteq", "\x022EC"),+    ("ntriangleright", "\x022EB"),+    ("ntrianglerighteq", "\x022ED"),+    ("nu", "\x003BD"),+    ("num", "\x00023") ]++reftab42 :: [(Text,Text)]+reftab42 =+  [ ("numero", "\x02116"),+    ("numsp", "\x02007"),+    ("nvDash", "\x022AD"),+    ("nvHarr", "\x02904"),+    ("nvap", "\x0224D\x020D2"),+    ("nvdash", "\x022AC"),+    ("nvge", "\x02265\x020D2"),+    ("nvgt", "\x0003E\x020D2"),+    ("nvinfin", "\x029DE"),+    ("nvlArr", "\x02902"),+    ("nvle", "\x02264\x020D2"),+    ("nvlt", "\x0003C\x020D2"),+    ("nvltrie", "\x022B4\x020D2"),+    ("nvrArr", "\x02903"),+    ("nvrtrie", "\x022B5\x020D2"),+    ("nvsim", "\x0223C\x020D2"),+    ("nwArr", "\x021D6"),+    ("nwarhk", "\x02923"),+    ("nwarr", "\x02196"),+    ("nwarrow", "\x02196"),+    ("nwnear", "\x02927"),+    ("oS", "\x024C8"),+    ("oacute", "\x000F3"),+    ("oast", "\x0229B"),+    ("ocir", "\x0229A"),+    ("ocirc", "\x000F4"),+    ("ocy", "\x0043E"),+    ("odash", "\x0229D"),+    ("odblac", "\x00151"),+    ("odiv", "\x02A38"),+    ("odot", "\x02299"),+    ("odsold", "\x029BC"),+    ("oelig", "\x00153"),+    ("ofcir", "\x029BF"),+    ("ofr", "\x1D52C"),+    ("ogon", "\x002DB"),+    ("ograve", "\x000F2") ]++reftab43 :: [(Text,Text)]+reftab43 =+  [ ("ogt", "\x029C1"),+    ("ohbar", "\x029B5"),+    ("ohm", "\x003A9"),+    ("oint", "\x0222E"),+    ("olarr", "\x021BA"),+    ("olcir", "\x029BE"),+    ("olcross", "\x029BB"),+    ("oline", "\x0203E"),+    ("olt", "\x029C0"),+    ("omacr", "\x0014D"),+    ("omega", "\x003C9"),+    ("omicron", "\x003BF"),+    ("omid", "\x029B6"),+    ("ominus", "\x02296"),+    ("oopf", "\x1D560"),+    ("opar", "\x029B7"),+    ("operp", "\x029B9"),+    ("oplus", "\x02295"),+    ("or", "\x02228"),+    ("orarr", "\x021BB"),+    ("ord", "\x02A5D"),+    ("order", "\x02134"),+    ("orderof", "\x02134"),+    ("ordf", "\x000AA"),+    ("ordm", "\x000BA"),+    ("origof", "\x022B6"),+    ("oror", "\x02A56"),+    ("orslope", "\x02A57"),+    ("orv", "\x02A5B"),+    ("oscr", "\x02134"),+    ("oslash", "\x000F8"),+    ("osol", "\x02298"),+    ("otilde", "\x000F5"),+    ("otimes", "\x02297"),+    ("otimesas", "\x02A36"),+    ("ouml", "\x000F6"),+    ("ovbar", "\x0233D") ]++reftab44 :: [(Text,Text)]+reftab44 =+  [ ("par", "\x02225"),+    ("para", "\x000B6"),+    ("parallel", "\x02225"),+    ("parsim", "\x02AF3"),+    ("parsl", "\x02AFD"),+    ("part", "\x02202"),+    ("pcy", "\x0043F"),+    ("percnt", "\x00025"),+    ("period", "\x0002E"),+    ("permil", "\x02030"),+    ("perp", "\x022A5"),+    ("pertenk", "\x02031"),+    ("pfr", "\x1D52D"),+    ("phi", "\x003C6"),+    ("phiv", "\x003D5"),+    ("phmmat", "\x02133"),+    ("phone", "\x0260E"),+    ("pi", "\x003C0"),+    ("pitchfork", "\x022D4"),+    ("piv", "\x003D6"),+    ("planck", "\x0210F"),+    ("planckh", "\x0210E"),+    ("plankv", "\x0210F"),+    ("plus", "\x0002B"),+    ("plusacir", "\x02A23"),+    ("plusb", "\x0229E"),+    ("pluscir", "\x02A22"),+    ("plusdo", "\x02214"),+    ("plusdu", "\x02A25"),+    ("pluse", "\x02A72"),+    ("plusmn", "\x000B1"),+    ("plussim", "\x02A26"),+    ("plustwo", "\x02A27"),+    ("pm", "\x000B1"),+    ("pointint", "\x02A15"),+    ("popf", "\x1D561"),+    ("pound", "\x000A3") ]++reftab45 :: [(Text,Text)]+reftab45 =+  [ ("pr", "\x0227A"),+    ("prE", "\x02AB3"),+    ("prap", "\x02AB7"),+    ("prcue", "\x0227C"),+    ("pre", "\x02AAF"),+    ("prec", "\x0227A"),+    ("precapprox", "\x02AB7"),+    ("preccurlyeq", "\x0227C"),+    ("preceq", "\x02AAF"),+    ("precnapprox", "\x02AB9"),+    ("precneqq", "\x02AB5"),+    ("precnsim", "\x022E8"),+    ("precsim", "\x0227E"),+    ("prime", "\x02032"),+    ("primes", "\x02119"),+    ("prnE", "\x02AB5"),+    ("prnap", "\x02AB9"),+    ("prnsim", "\x022E8"),+    ("prod", "\x0220F"),+    ("profalar", "\x0232E"),+    ("profline", "\x02312"),+    ("profsurf", "\x02313"),+    ("prop", "\x0221D"),+    ("propto", "\x0221D"),+    ("prsim", "\x0227E"),+    ("prurel", "\x022B0"),+    ("pscr", "\x1D4C5"),+    ("psi", "\x003C8"),+    ("puncsp", "\x02008"),+    ("qfr", "\x1D52E"),+    ("qint", "\x02A0C"),+    ("qopf", "\x1D562"),+    ("qprime", "\x02057"),+    ("qscr", "\x1D4C6"),+    ("quaternions", "\x0210D"),+    ("quatint", "\x02A16"),+    ("quest", "\x0003F") ]++reftab46 :: [(Text,Text)]+reftab46 =+  [ ("questeq", "\x0225F"),+    ("quot", "\x00022"),+    ("rAarr", "\x021DB"),+    ("rArr", "\x021D2"),+    ("rAtail", "\x0291C"),+    ("rBarr", "\x0290F"),+    ("rHar", "\x02964"),+    ("race", "\x0223D\x00331"),+    ("racute", "\x00155"),+    ("radic", "\x0221A"),+    ("raemptyv", "\x029B3"),+    ("rang", "\x027E9"),+    ("rangd", "\x02992"),+    ("range", "\x029A5"),+    ("rangle", "\x027E9"),+    ("raquo", "\x000BB"),+    ("rarr", "\x02192"),+    ("rarrap", "\x02975"),+    ("rarrb", "\x021E5"),+    ("rarrbfs", "\x02920"),+    ("rarrc", "\x02933"),+    ("rarrfs", "\x0291E"),+    ("rarrhk", "\x021AA"),+    ("rarrlp", "\x021AC"),+    ("rarrpl", "\x02945"),+    ("rarrsim", "\x02974"),+    ("rarrtl", "\x021A3"),+    ("rarrw", "\x0219D"),+    ("ratail", "\x0291A"),+    ("ratio", "\x02236"),+    ("rationals", "\x0211A"),+    ("rbarr", "\x0290D"),+    ("rbbrk", "\x02773"),+    ("rbrace", "\x0007D"),+    ("rbrack", "\x0005D"),+    ("rbrke", "\x0298C"),+    ("rbrksld", "\x0298E") ]++reftab47 :: [(Text,Text)]+reftab47 =+  [ ("rbrkslu", "\x02990"),+    ("rcaron", "\x00159"),+    ("rcedil", "\x00157"),+    ("rceil", "\x02309"),+    ("rcub", "\x0007D"),+    ("rcy", "\x00440"),+    ("rdca", "\x02937"),+    ("rdldhar", "\x02969"),+    ("rdquo", "\x0201D"),+    ("rdquor", "\x0201D"),+    ("rdsh", "\x021B3"),+    ("real", "\x0211C"),+    ("realine", "\x0211B"),+    ("realpart", "\x0211C"),+    ("reals", "\x0211D"),+    ("rect", "\x025AD"),+    ("reg", "\x000AE"),+    ("rfisht", "\x0297D"),+    ("rfloor", "\x0230B"),+    ("rfr", "\x1D52F"),+    ("rhard", "\x021C1"),+    ("rharu", "\x021C0"),+    ("rharul", "\x0296C"),+    ("rho", "\x003C1"),+    ("rhov", "\x003F1"),+    ("rightarrow", "\x02192"),+    ("rightarrowtail", "\x021A3"),+    ("rightharpoondown", "\x021C1"),+    ("rightharpoonup", "\x021C0"),+    ("rightleftarrows", "\x021C4"),+    ("rightleftharpoons", "\x021CC"),+    ("rightrightarrows", "\x021C9"),+    ("rightsquigarrow", "\x0219D"),+    ("rightthreetimes", "\x022CC"),+    ("ring", "\x002DA"),+    ("risingdotseq", "\x02253"),+    ("rlarr", "\x021C4") ]++reftab48 :: [(Text,Text)]+reftab48 =+  [ ("rlhar", "\x021CC"),+    ("rlm", "\x0200F"),+    ("rmoust", "\x023B1"),+    ("rmoustache", "\x023B1"),+    ("rnmid", "\x02AEE"),+    ("roang", "\x027ED"),+    ("roarr", "\x021FE"),+    ("robrk", "\x027E7"),+    ("ropar", "\x02986"),+    ("ropf", "\x1D563"),+    ("roplus", "\x02A2E"),+    ("rotimes", "\x02A35"),+    ("rpar", "\x00029"),+    ("rpargt", "\x02994"),+    ("rppolint", "\x02A12"),+    ("rrarr", "\x021C9"),+    ("rsaquo", "\x0203A"),+    ("rscr", "\x1D4C7"),+    ("rsh", "\x021B1"),+    ("rsqb", "\x0005D"),+    ("rsquo", "\x02019"),+    ("rsquor", "\x02019"),+    ("rthree", "\x022CC"),+    ("rtimes", "\x022CA"),+    ("rtri", "\x025B9"),+    ("rtrie", "\x022B5"),+    ("rtrif", "\x025B8"),+    ("rtriltri", "\x029CE"),+    ("ruluhar", "\x02968"),+    ("rx", "\x0211E"),+    ("sacute", "\x0015B"),+    ("sbquo", "\x0201A"),+    ("sc", "\x0227B"),+    ("scE", "\x02AB4"),+    ("scap", "\x02AB8"),+    ("scaron", "\x00161"),+    ("sccue", "\x0227D") ]++reftab49 :: [(Text,Text)]+reftab49 =+  [ ("sce", "\x02AB0"),+    ("scedil", "\x0015F"),+    ("scirc", "\x0015D"),+    ("scnE", "\x02AB6"),+    ("scnap", "\x02ABA"),+    ("scnsim", "\x022E9"),+    ("scpolint", "\x02A13"),+    ("scsim", "\x0227F"),+    ("scy", "\x00441"),+    ("sdot", "\x022C5"),+    ("sdotb", "\x022A1"),+    ("sdote", "\x02A66"),+    ("seArr", "\x021D8"),+    ("searhk", "\x02925"),+    ("searr", "\x02198"),+    ("searrow", "\x02198"),+    ("sect", "\x000A7"),+    ("semi", "\x0003B"),+    ("seswar", "\x02929"),+    ("setminus", "\x02216"),+    ("setmn", "\x02216"),+    ("sext", "\x02736"),+    ("sfr", "\x1D530"),+    ("sfrown", "\x02322"),+    ("sharp", "\x0266F"),+    ("shchcy", "\x00449"),+    ("shcy", "\x00448"),+    ("shortmid", "\x02223"),+    ("shortparallel", "\x02225"),+    ("shy", "\x000AD"),+    ("sigma", "\x003C3"),+    ("sigmaf", "\x003C2"),+    ("sigmav", "\x003C2"),+    ("sim", "\x0223C"),+    ("simdot", "\x02A6A"),+    ("sime", "\x02243"),+    ("simeq", "\x02243") ]++reftab50 :: [(Text,Text)]+reftab50 =+  [ ("simg", "\x02A9E"),+    ("simgE", "\x02AA0"),+    ("siml", "\x02A9D"),+    ("simlE", "\x02A9F"),+    ("simne", "\x02246"),+    ("simplus", "\x02A24"),+    ("simrarr", "\x02972"),+    ("slarr", "\x02190"),+    ("smallsetminus", "\x02216"),+    ("smashp", "\x02A33"),+    ("smeparsl", "\x029E4"),+    ("smid", "\x02223"),+    ("smile", "\x02323"),+    ("smt", "\x02AAA"),+    ("smte", "\x02AAC"),+    ("smtes", "\x02AAC\x0FE00"),+    ("softcy", "\x0044C"),+    ("sol", "\x0002F"),+    ("solb", "\x029C4"),+    ("solbar", "\x0233F"),+    ("sopf", "\x1D564"),+    ("spades", "\x02660"),+    ("spadesuit", "\x02660"),+    ("spar", "\x02225"),+    ("sqcap", "\x02293"),+    ("sqcaps", "\x02293\x0FE00"),+    ("sqcup", "\x02294"),+    ("sqcups", "\x02294\x0FE00"),+    ("sqsub", "\x0228F"),+    ("sqsube", "\x02291"),+    ("sqsubset", "\x0228F"),+    ("sqsubseteq", "\x02291"),+    ("sqsup", "\x02290"),+    ("sqsupe", "\x02292"),+    ("sqsupset", "\x02290"),+    ("sqsupseteq", "\x02292"),+    ("squ", "\x025A1") ]++reftab51 :: [(Text,Text)]+reftab51 =+  [ ("square", "\x025A1"),+    ("squarf", "\x025AA"),+    ("squf", "\x025AA"),+    ("srarr", "\x02192"),+    ("sscr", "\x1D4C8"),+    ("ssetmn", "\x02216"),+    ("ssmile", "\x02323"),+    ("sstarf", "\x022C6"),+    ("star", "\x02606"),+    ("starf", "\x02605"),+    ("straightepsilon", "\x003F5"),+    ("straightphi", "\x003D5"),+    ("strns", "\x000AF"),+    ("sub", "\x02282"),+    ("subE", "\x02AC5"),+    ("subdot", "\x02ABD"),+    ("sube", "\x02286"),+    ("subedot", "\x02AC3"),+    ("submult", "\x02AC1"),+    ("subnE", "\x02ACB"),+    ("subne", "\x0228A"),+    ("subplus", "\x02ABF"),+    ("subrarr", "\x02979"),+    ("subset", "\x02282"),+    ("subseteq", "\x02286"),+    ("subseteqq", "\x02AC5"),+    ("subsetneq", "\x0228A"),+    ("subsetneqq", "\x02ACB"),+    ("subsim", "\x02AC7"),+    ("subsub", "\x02AD5"),+    ("subsup", "\x02AD3"),+    ("succ", "\x0227B"),+    ("succapprox", "\x02AB8"),+    ("succcurlyeq", "\x0227D"),+    ("succeq", "\x02AB0"),+    ("succnapprox", "\x02ABA"),+    ("succneqq", "\x02AB6") ]++reftab52 :: [(Text,Text)]+reftab52 =+  [ ("succnsim", "\x022E9"),+    ("succsim", "\x0227F"),+    ("sum", "\x02211"),+    ("sung", "\x0266A"),+    ("sup", "\x02283"),+    ("sup1", "\x000B9"),+    ("sup2", "\x000B2"),+    ("sup3", "\x000B3"),+    ("supE", "\x02AC6"),+    ("supdot", "\x02ABE"),+    ("supdsub", "\x02AD8"),+    ("supe", "\x02287"),+    ("supedot", "\x02AC4"),+    ("suphsol", "\x027C9"),+    ("suphsub", "\x02AD7"),+    ("suplarr", "\x0297B"),+    ("supmult", "\x02AC2"),+    ("supnE", "\x02ACC"),+    ("supne", "\x0228B"),+    ("supplus", "\x02AC0"),+    ("supset", "\x02283"),+    ("supseteq", "\x02287"),+    ("supseteqq", "\x02AC6"),+    ("supsetneq", "\x0228B"),+    ("supsetneqq", "\x02ACC"),+    ("supsim", "\x02AC8"),+    ("supsub", "\x02AD4"),+    ("supsup", "\x02AD6"),+    ("swArr", "\x021D9"),+    ("swarhk", "\x02926"),+    ("swarr", "\x02199"),+    ("swarrow", "\x02199"),+    ("swnwar", "\x0292A"),+    ("szlig", "\x000DF"),+    ("target", "\x02316"),+    ("tau", "\x003C4"),+    ("tbrk", "\x023B4") ]++reftab53 :: [(Text,Text)]+reftab53 =+  [ ("tcaron", "\x00165"),+    ("tcedil", "\x00163"),+    ("tcy", "\x00442"),+    ("tdot", "\x020DB"),+    ("telrec", "\x02315"),+    ("tfr", "\x1D531"),+    ("there4", "\x02234"),+    ("therefore", "\x02234"),+    ("theta", "\x003B8"),+    ("thetasym", "\x003D1"),+    ("thetav", "\x003D1"),+    ("thickapprox", "\x02248"),+    ("thicksim", "\x0223C"),+    ("thinsp", "\x02009"),+    ("thkap", "\x02248"),+    ("thksim", "\x0223C"),+    ("thorn", "\x000FE"),+    ("tilde", "\x002DC"),+    ("times", "\x000D7"),+    ("timesb", "\x022A0"),+    ("timesbar", "\x02A31"),+    ("timesd", "\x02A30"),+    ("tint", "\x0222D"),+    ("toea", "\x02928"),+    ("top", "\x022A4"),+    ("topbot", "\x02336"),+    ("topcir", "\x02AF1"),+    ("topf", "\x1D565"),+    ("topfork", "\x02ADA"),+    ("tosa", "\x02929"),+    ("tprime", "\x02034"),+    ("trade", "\x02122"),+    ("triangle", "\x025B5"),+    ("triangledown", "\x025BF"),+    ("triangleleft", "\x025C3"),+    ("trianglelefteq", "\x022B4"),+    ("triangleq", "\x0225C") ]++reftab54 :: [(Text,Text)]+reftab54 =+  [ ("triangleright", "\x025B9"),+    ("trianglerighteq", "\x022B5"),+    ("tridot", "\x025EC"),+    ("trie", "\x0225C"),+    ("triminus", "\x02A3A"),+    ("triplus", "\x02A39"),+    ("trisb", "\x029CD"),+    ("tritime", "\x02A3B"),+    ("trpezium", "\x023E2"),+    ("tscr", "\x1D4C9"),+    ("tscy", "\x00446"),+    ("tshcy", "\x0045B"),+    ("tstrok", "\x00167"),+    ("twixt", "\x0226C"),+    ("twoheadleftarrow", "\x0219E"),+    ("twoheadrightarrow", "\x021A0"),+    ("uArr", "\x021D1"),+    ("uHar", "\x02963"),+    ("uacute", "\x000FA"),+    ("uarr", "\x02191"),+    ("ubrcy", "\x0045E"),+    ("ubreve", "\x0016D"),+    ("ucirc", "\x000FB"),+    ("ucy", "\x00443"),+    ("udarr", "\x021C5"),+    ("udblac", "\x00171"),+    ("udhar", "\x0296E"),+    ("ufisht", "\x0297E"),+    ("ufr", "\x1D532"),+    ("ugrave", "\x000F9"),+    ("uharl", "\x021BF"),+    ("uharr", "\x021BE"),+    ("uhblk", "\x02580"),+    ("ulcorn", "\x0231C"),+    ("ulcorner", "\x0231C"),+    ("ulcrop", "\x0230F"),+    ("ultri", "\x025F8") ]++reftab55 :: [(Text,Text)]+reftab55 =+  [ ("umacr", "\x0016B"),+    ("uml", "\x000A8"),+    ("uogon", "\x00173"),+    ("uopf", "\x1D566"),+    ("uparrow", "\x02191"),+    ("updownarrow", "\x02195"),+    ("upharpoonleft", "\x021BF"),+    ("upharpoonright", "\x021BE"),+    ("uplus", "\x0228E"),+    ("upsi", "\x003C5"),+    ("upsih", "\x003D2"),+    ("upsilon", "\x003C5"),+    ("upuparrows", "\x021C8"),+    ("urcorn", "\x0231D"),+    ("urcorner", "\x0231D"),+    ("urcrop", "\x0230E"),+    ("uring", "\x0016F"),+    ("urtri", "\x025F9"),+    ("uscr", "\x1D4CA"),+    ("utdot", "\x022F0"),+    ("utilde", "\x00169"),+    ("utri", "\x025B5"),+    ("utrif", "\x025B4"),+    ("uuarr", "\x021C8"),+    ("uuml", "\x000FC"),+    ("uwangle", "\x029A7"),+    ("vArr", "\x021D5"),+    ("vBar", "\x02AE8"),+    ("vBarv", "\x02AE9"),+    ("vDash", "\x022A8"),+    ("vangrt", "\x0299C"),+    ("varepsilon", "\x003F5"),+    ("varkappa", "\x003F0"),+    ("varnothing", "\x02205"),+    ("varphi", "\x003D5"),+    ("varpi", "\x003D6"),+    ("varpropto", "\x0221D") ]++reftab56 :: [(Text,Text)]+reftab56 =+  [ ("varr", "\x02195"),+    ("varrho", "\x003F1"),+    ("varsigma", "\x003C2"),+    ("varsubsetneq", "\x0228A\x0FE00"),+    ("varsubsetneqq", "\x02ACB\x0FE00"),+    ("varsupsetneq", "\x0228B\x0FE00"),+    ("varsupsetneqq", "\x02ACC\x0FE00"),+    ("vartheta", "\x003D1"),+    ("vartriangleleft", "\x022B2"),+    ("vartriangleright", "\x022B3"),+    ("vcy", "\x00432"),+    ("vdash", "\x022A2"),+    ("vee", "\x02228"),+    ("veebar", "\x022BB"),+    ("veeeq", "\x0225A"),+    ("vellip", "\x022EE"),+    ("verbar", "\x0007C"),+    ("vert", "\x0007C"),+    ("vfr", "\x1D533"),+    ("vltri", "\x022B2"),+    ("vnsub", "\x02282\x020D2"),+    ("vnsup", "\x02283\x020D2"),+    ("vopf", "\x1D567"),+    ("vprop", "\x0221D"),+    ("vrtri", "\x022B3"),+    ("vscr", "\x1D4CB"),+    ("vsubnE", "\x02ACB\x0FE00"),+    ("vsubne", "\x0228A\x0FE00"),+    ("vsupnE", "\x02ACC\x0FE00"),+    ("vsupne", "\x0228B\x0FE00"),+    ("vzigzag", "\x0299A"),+    ("wcirc", "\x00175"),+    ("wedbar", "\x02A5F"),+    ("wedge", "\x02227"),+    ("wedgeq", "\x02259"),+    ("weierp", "\x02118"),+    ("wfr", "\x1D534") ]++reftab57 :: [(Text,Text)]+reftab57 =+  [ ("wopf", "\x1D568"),+    ("wp", "\x02118"),+    ("wr", "\x02240"),+    ("wreath", "\x02240"),+    ("wscr", "\x1D4CC"),+    ("xcap", "\x022C2"),+    ("xcirc", "\x025EF"),+    ("xcup", "\x022C3"),+    ("xdtri", "\x025BD"),+    ("xfr", "\x1D535"),+    ("xhArr", "\x027FA"),+    ("xharr", "\x027F7"),+    ("xi", "\x003BE"),+    ("xlArr", "\x027F8"),+    ("xlarr", "\x027F5"),+    ("xmap", "\x027FC"),+    ("xnis", "\x022FB"),+    ("xodot", "\x02A00"),+    ("xopf", "\x1D569"),+    ("xoplus", "\x02A01"),+    ("xotime", "\x02A02"),+    ("xrArr", "\x027F9"),+    ("xrarr", "\x027F6"),+    ("xscr", "\x1D4CD"),+    ("xsqcup", "\x02A06"),+    ("xuplus", "\x02A04"),+    ("xutri", "\x025B3"),+    ("xvee", "\x022C1"),+    ("xwedge", "\x022C0"),+    ("yacute", "\x000FD"),+    ("yacy", "\x0044F"),+    ("ycirc", "\x00177"),+    ("ycy", "\x0044B"),+    ("yen", "\x000A5"),+    ("yfr", "\x1D536"),+    ("yicy", "\x00457"),+    ("yopf", "\x1D56A") ]++reftab58 :: [(Text,Text)]+reftab58 =+  [ ("yscr", "\x1D4CE"),+    ("yucy", "\x0044E"),+    ("yuml", "\x000FF"),+    ("zacute", "\x0017A"),+    ("zcaron", "\x0017E"),+    ("zcy", "\x00437"),+    ("zdot", "\x0017C"),+    ("zeetrf", "\x02128"),+    ("zeta", "\x003B6"),+    ("zfr", "\x1D537"),+    ("zhcy", "\x00436"),+    ("zigrarr", "\x021DD"),+    ("zopf", "\x1D56B"),+    ("zscr", "\x1D4CF"),+    ("zwj", "\x0200D"),+    ("zwnj", "\x0200C") ]+
+ src/Text/XmlHtml/HTML/Parse.hs view
@@ -0,0 +1,388 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TupleSections     #-}++module Text.XmlHtml.HTML.Parse where++import           Control.Applicative+import           Control.Monad+import           Data.Char+import           Data.List+import           Data.Maybe+import           Text.XmlHtml.Common+import           Text.XmlHtml.HTML.Meta+import           Text.XmlHtml.TextParser+import qualified Text.XmlHtml.XML.Parse as XML++import qualified Text.Parsec as P++import qualified Data.Set as S+import qualified Data.Map as M++import           Data.Text (Text)+import qualified Data.Text as T+++------------------------------------------------------------------------------+-- | HTML version of document fragment parsing rule  It differs only in that+-- it parses the HTML version of 'content' and returns an 'HtmlDocument'.+docFragment :: Encoding -> Parser Document+docFragment e = do+    (dt, nodes1)      <- prolog+    (nodes2, Matched) <- content Nothing+    return $ HtmlDocument e dt (nodes1 ++ nodes2)+++------------------------------------------------------------------------------+-- Parsing code                                                             --+------------------------------------------------------------------------------++{-+    The following are the differences between this code and the straight XML+    parsing code.+    +    1. HTML void tags (area, base, etc.) are always treated as empty tags,+       regardless of whether they have the empty-tag slash.++    2. HTML raw text tags (script and style) are parsed as straight text+       with neither markup nor references, except that they end at the first+       syntactically valid matching end tag.++    3. HTML RCDATA tags (textarea and title) are parsed as text and references+       but no other markup, except that they end at the first syntactically+       valid matching end tag.++    4. End tags need only match their corresponding start tags in a case+       insensitive comparison.  In case they are different, the start tag is+       used for the element tag name.++    5. Hexadecimal char references may use &#X...; (capital X)  -- DONE++    6. Attribute names are allowed to consist of any text except for control+       characters, space, '\"', '\'', '>', '/', or '='.++    7. Empty attribute syntax is allowed (an attribute not followed by an eq).+       In this case, the attribute value is considered to be the empty string.++    8. Quoted attribute syntax is relaxed to allow any character except for the+       matching quote.  References are allowed.++    9. Attribute values may be unquoted.  In this case, the attribute value may+       not contain space, single or double quotes, '=', '<', '>', or '`', and+       may not be the empty string.  It can still contain references.++    10. There are many more character references available.++    11. Only "ambiguous" ampersands are prohibited in character data.  This+        means ampersands that parse like character or entity references.++    12. Omittable end tags are inserted automatically.++    13. DOCTYPE tags matched with case insensitive keywords.+-}+++------------------------------------------------------------------------------+prolog :: Parser (Maybe DocType, [Node])+prolog = do+    _      <- optional XML.xmlDecl+    nodes1 <- many XML.misc+    rest   <- optional $ do+        dt     <- docTypeDecl+        nodes2 <- many XML.misc+        return (dt, nodes2)+    case rest of+        Nothing           -> return (Nothing, catMaybes nodes1)+        Just (dt, nodes2) -> return (Just dt, catMaybes (nodes1 ++ nodes2))+++------------------------------------------------------------------------------+-- | Internal subset is parsed, but ignored since we don't have data types to+-- store it.+docTypeDecl :: Parser DocType+docTypeDecl = do+    P.try $ do+        _      <- text "<!"+        decl   <- XML.name+        when (T.toLower decl /= "doctype") $ fail "Expected DOCTYPE"+    XML.whiteSpace+    tag    <- XML.name+    _      <- optional XML.whiteSpace+    extid  <- externalID+    _      <- optional XML.whiteSpace+    intsub <- XML.internalDoctype+    _      <- P.char '>'+    return (DocType tag extid intsub)+++------------------------------------------------------------------------------+externalID :: Parser ExternalID+externalID = do+    tok  <- optional $ T.toLower <$> XML.name+    case tok of+        Just "system" -> systemID+        Just "public" -> publicID+        Just _        -> fail "Expected SYSTEM or PUBLIC"+        Nothing       -> return NoExternalID+  where+    systemID = do+        XML.whiteSpace+        System <$> XML.systemLiteral+    publicID = do+        XML.whiteSpace+        pid <- XML.pubIdLiteral+        XML.whiteSpace+        sid <- XML.systemLiteral+        return (Public pid sid)+++------------------------------------------------------------------------------+-- | Reads text and references, up until the passed-in parser succeeds.+-- (Generally, the passed in parser should be an end tag parser for the+-- RCDATA element.)+rcdata :: [Char] -> Parser a -> Parser Node+rcdata cs end = TextNode <$> T.concat <$> P.manyTill part end+  where part = takeWhile1 (not . (`elem` cs))+             <|> reference+             <|> T.singleton <$> P.anyChar+++------------------------------------------------------------------------------+-- | When parsing an element, three things can happen (besides failure):+-- +-- (1) The end tag matches the start tag.  This is a Matched.+-- +-- (2) The end tag does not match, but the element has an end tag that can be+-- omitted when there is no more content in its parent.  This is an+-- ImplicitLast.  In this case, we need to remember the tag name of the+-- end tag that we did find, so as to match it later.+-- +-- (3) A start tag is found such that it implicitly ends the current element.+-- This is an ImplicitNext.  In this case, we parse and remember the+-- entire element that comes next, so that it can be inserted after the+-- element being parsed.+data ElemResult = Matched+                | ImplicitLast Text+                | ImplicitNext Text [(Text, Text)] Bool+++------------------------------------------------------------------------------+finishElement :: Text -> [(Text, Text)] -> Bool -> Parser (Node, ElemResult)+finishElement t a b = do+    if b then return (Element t a [], Matched)+         else nonEmptyElem+  where+    nonEmptyElem+        | T.map toLower t `S.member` rawTextTags = do+            c <- XML.cdata  "<"  $ P.try (endTag t)+            return (Element t a [c], Matched)+        | T.map toLower t `S.member` rcdataTags = do+            c <- rcdata "&<" $ P.try (endTag t)+            return (Element t a [c], Matched)+        | T.map toLower t `S.member` endOmittableLast = tagContents optional+        | otherwise                                   = tagContents (fmap Just)+    tagContents modifier = do+        (c,r1) <- content (Just t)+        case r1 of+            Matched -> do+                r2 <- modifier (endTag t)+                case r2 of+                    Nothing -> return (Element t a c, Matched)+                    Just rr -> return (Element t a c, rr)+            ImplicitLast tag | T.map toLower tag == T.map toLower t -> do+                return (Element t a c, Matched)+            end -> do+                return (Element t a c, end)+++------------------------------------------------------------------------------+emptyOrStartTag :: Parser (Text, [(Text, Text)], Bool)+emptyOrStartTag = do+    t <- P.try $ P.char '<' *> XML.name+    a <- many $ P.try $ do+        XML.whiteSpace+        attribute+    when (hasDups a) $ fail "Duplicate attribute names in element"+    _ <- optional XML.whiteSpace+    e <- fmap isJust $ optional (P.char '/')+    let e' = e || (T.map toLower t `S.member` voidTags)+    _ <- P.char '>'+    return (t, a, e')+  where+    hasDups a = length (nub (map fst a)) < length a+++------------------------------------------------------------------------------+attrName :: Parser Text+attrName = takeWhile1 isAttrName+  where isAttrName c | c `elem` "\0 \"\'>/=" = False+                     | isControlChar c       = False+                     | otherwise             = True+++------------------------------------------------------------------------------+-- | From 8.2.2.3 of the HTML 5 spec, omitting the very high control+-- characters because they are unlikely to occur and I got tired of typing.+isControlChar :: Char -> Bool+isControlChar c | c >= '\x007F' && c <= '\x009F' = True+                | c >= '\xFDD0' && c <= '\xFDEF' = True+                | otherwise                      = False+++------------------------------------------------------------------------------+quotedAttrValue :: Parser Text+quotedAttrValue = singleQuoted <|> doubleQuoted+  where+    singleQuoted = P.char '\'' *> refTill "&\'" <* P.char '\''+    doubleQuoted = P.char '\"' *> refTill "&\"" <* P.char '\"'+    refTill end = T.concat <$> many+        (takeWhile1 (not . (`elem` end)) <|> reference)+++------------------------------------------------------------------------------+unquotedAttrValue :: Parser Text+unquotedAttrValue = refTill " \"\'=<>&`"+  where+    refTill end = T.concat <$> some+        (takeWhile1 (not . (`elem` end)) <|> reference)+++------------------------------------------------------------------------------+attrValue :: Parser Text+attrValue = quotedAttrValue <|> unquotedAttrValue+++------------------------------------------------------------------------------+attribute :: Parser (Text, Text)+attribute = do+    n <- attrName+    _ <- optional XML.whiteSpace+    v <- optional $ do+        _ <- P.char '='+        _ <- optional XML.whiteSpace+        attrValue+    return $ maybe (n,"") (n,) v+++------------------------------------------------------------------------------+endTag :: Text -> Parser ElemResult+endTag s = do+    _ <- text "</"+    t <- XML.name+    r <- if (T.map toLower s == T.map toLower t)+            then return Matched+            else if T.map toLower s `S.member` endOmittableLast+                then return (ImplicitLast t)+                else fail $ "mismatched tags: </" ++ T.unpack t +++                            "> found inside <" ++ T.unpack s ++ "> tag"+    _ <- optional XML.whiteSpace+    _ <- text ">"+    return r+++------------------------------------------------------------------------------+content :: Maybe Text -> Parser ([Node], ElemResult)+content parent = do+    (ns, end) <- readText+    return (coalesceText (catMaybes ns), end)+  where+    readText     = do+        s <- optional XML.charData+        t <- optional whileMatched+        case t of+            Nothing      -> return ([s], Matched)+            Just (tt, m) -> return (s:tt, m)++    whileMatched = do+        (n,end) <- (,Matched) <$> (:[]) <$> Just <$> TextNode <$> reference+               <|> (,Matched) <$> (:[]) <$> XML.cdSect+               <|> (,Matched) <$> (:[]) <$> XML.processingInstruction+               <|> (,Matched) <$> (:[]) <$> XML.comment+               <|> doElement+        case end of+            Matched -> do+                (ns, end') <- readText+                return (n ++ ns, end')+            _ -> do+                return (n, end)++    doElement = do+        (t,a,b) <- emptyOrStartTag+        handle t a b++    handle t a b = do+        if breaksTag t parent+            then return ([Nothing], ImplicitNext t a b)+            else do+                (n,end) <- finishElement t a b+                case end of+                    ImplicitNext t' a' b' -> do+                        (ns,end') <- handle t' a' b'+                        return (Just n : ns, end')+                    _ -> return ([Just n], end)++    breaksTag _     Nothing       = False+    breaksTag child (Just tag) = case M.lookup tag endOmittableNext of+        Nothing -> False+        Just s  -> S.member child s++    coalesceText (TextNode s : TextNode t : ns)+        = coalesceText (TextNode (T.append s t) : ns)+    coalesceText (n:ns)+        = n : coalesceText ns+    coalesceText []+        = []+++------------------------------------------------------------------------------+reference :: Parser Text+reference = do+    _    <- P.char '&'+    r    <- (Left  <$> P.try finishCharRef)+        <|> (Right <$> P.try finishEntityRef)+        <|> (Left  <$> return '&')+    case r of+        Left c   -> do+            when (not (isValidChar c)) $ fail $+                "Reference is not a valid character"+            return (T.singleton c)+        Right nm -> case M.lookup nm predefinedRefs of+            Nothing -> fail $ "Unknown entity reference: " ++ T.unpack nm+            Just t  -> return t+++------------------------------------------------------------------------------+finishCharRef :: Parser Char+finishCharRef = P.char '#' *> (hexCharRef <|> decCharRef)+  where+    decCharRef = do+        ds <- some digit+        _ <- P.char ';'+        let c = chr $ foldl' (\a b -> 10 * a + b) 0 ds+        return c+      where+        digit = do+            d <- P.satisfy (\c -> c >= '0' && c <= '9')+            return (ord d - ord '0')+    hexCharRef = do+        _ <- P.char 'x' <|> P.char 'X'+        ds <- some digit+        _ <- P.char ';'+        let c = chr $ foldl' (\a b -> 16 * a + b) 0 ds+        return c+      where+        digit = num <|> upper <|> lower+        num = do+            d <- P.satisfy (\c -> c >= '0' && c <= '9')+            return (ord d - ord '0')+        upper = do+            d <- P.satisfy (\c -> c >= 'A' && c <= 'F')+            return (10 + ord d - ord 'A')+        lower = do+            d <- P.satisfy (\c -> c >= 'a' && c <= 'f')+            return (10 + ord d - ord 'a')+++------------------------------------------------------------------------------+finishEntityRef :: Parser Text+finishEntityRef = XML.name <* P.char ';'+
+ src/Text/XmlHtml/HTML/Render.hs view
@@ -0,0 +1,148 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PatternGuards     #-}++module Text.XmlHtml.HTML.Render where++import           Blaze.ByteString.Builder+import           Control.Applicative+import           Data.Maybe+import           Data.Monoid+import qualified Text.Parsec as P+import           Text.XmlHtml.Common+import           Text.XmlHtml.TextParser+import           Text.XmlHtml.HTML.Meta+import qualified Text.XmlHtml.HTML.Parse as P+import           Text.XmlHtml.XML.Render (docTypeDecl, entity)++import           Data.Text (Text)+import qualified Data.Text as T++import qualified Data.Set as S++------------------------------------------------------------------------------+-- | And, the rendering code.+render :: Encoding -> Maybe DocType -> [Node] -> Builder+render e dt ns = byteOrder+       `mappend` docTypeDecl e dt+       `mappend` nodes+    where byteOrder | isUTF16 e = fromText e "\xFEFF" -- byte order mark+                    | otherwise = mempty+          nodes | null ns   = mempty+                | otherwise = firstNode e (head ns)+                    `mappend` (mconcat $ map (node e) (tail ns))+++------------------------------------------------------------------------------+-- | HTML allows & so long as it is not "ambiguous" (i.e., looks like an+-- entity).  So we have a special case for that.+escaped :: [Char] -> Encoding -> Text -> Builder+escaped _   _ "" = mempty+escaped bad e t  =+    let (p,s) = T.break (`elem` bad) t+        r     = T.uncons s+    in  fromText e p `mappend` case r of+            Nothing+                -> mempty+            Just ('&',ss) | isLeft (parseText ambigAmp "" s)+                -> fromText e "&" `mappend` escaped bad e ss+            Just (c,ss)+                -> entity e c `mappend` escaped bad e ss+  where isLeft   = either (const True) (const False)+        ambigAmp = P.char '&' *>+            (P.finishCharRef *> return () <|> P.finishEntityRef *> return ())+++------------------------------------------------------------------------------+node :: Encoding -> Node -> Builder+node e (TextNode t)                        = escaped "<>&" e t+node e (Comment t) | "--" `T.isInfixOf`  t = error "Invalid comment"+                   | "-"  `T.isSuffixOf` t = error "Invalid comment"+                   | otherwise             = fromText e "<!--"+                                             `mappend` fromText e t+                                             `mappend` fromText e "-->"+node e (Element t a c)                     = element e t a c+++------------------------------------------------------------------------------+-- | Process the first node differently to encode leading whitespace.  This+-- lets us be sure that @parseHTML@ is a left inverse to @render@.+firstNode :: Encoding -> Node -> Builder+firstNode e (Comment t)     = node e (Comment t)+firstNode e (Element t a c) = node e (Element t a c)+firstNode _ (TextNode "")   = mempty+firstNode e (TextNode t)    = let (c,t') = fromJust $ T.uncons t+                              in escaped "<>& \t\r\n" e (T.singleton c)+                                 `mappend` node e (TextNode t')+++------------------------------------------------------------------------------+-- XXX: Should do something to avoid concatting large CDATA sections before+-- writing them to the output.+element :: Encoding -> Text -> [(Text, Text)] -> [Node] -> Builder+element e t a c+    | t `S.member` voidTags && null c         =+        fromText e "<"+        `mappend` fromText e t+        `mappend` (mconcat $ map (attribute e) a)+        `mappend` fromText e " />"+    | t `S.member` voidTags                   =+        error $ T.unpack t ++ " must be empty"+    | t `S.member` rawTextTags,+      all isTextNode c,+      let s = T.concat (map nodeText c),+      not ("</" `T.append` t `T.isInfixOf` s) =+        fromText e "<"+        `mappend` fromText e t+        `mappend` (mconcat $ map (attribute e) a)+        `mappend` fromText e ">"+        `mappend` fromText e s+        `mappend` fromText e "</"+        `mappend` fromText e t+        `mappend` fromText e ">"+    | t `S.member` rawTextTags,+      [ TextNode _ ] <- c                     =+        error $ T.unpack t ++ " cannot contain text looking like its end tag"+    | t `S.member` rawTextTags                =+        error $ T.unpack t ++ " cannot contain child elements or comments"+    | t `S.member` rcdataTags,+      all isTextNode c                        =+        fromText e "<"+        `mappend` fromText e t+        `mappend` (mconcat $ map (attribute e) a)+        `mappend` fromText e ">"+        `mappend` mconcat (map (escaped "<&" e . nodeText) c)+        `mappend` fromText e "</"+        `mappend` fromText e t+        `mappend` fromText e ">"+    | t `S.member` rcdataTags                 =+        error $ T.unpack t ++ " cannot contain child elements or comments"+    | otherwise =+        fromText e "<"+        `mappend` fromText e t+        `mappend` (mconcat $ map (attribute e) a)+        `mappend` fromText e ">"+        `mappend` (mconcat $ map (node e) c)+        `mappend` fromText e "</"+        `mappend` fromText e t+        `mappend` fromText e ">"+++------------------------------------------------------------------------------+attribute :: Encoding -> (Text, Text) -> Builder+attribute e (n,v)+    | v == ""                    =+        fromText e " "+        `mappend` fromText e n+    | not ("\'" `T.isInfixOf` v) =+        fromText e " "+        `mappend` fromText e n+        `mappend` fromText e "=\'"+        `mappend` escaped "&" e v+        `mappend` fromText e "\'"+    | otherwise                  =+        fromText e " "+        `mappend` fromText e n+        `mappend` fromText e "=\""+        `mappend` escaped "&\"" e v+        `mappend` fromText e "\""+
+ src/Text/XmlHtml/TextParser.hs view
@@ -0,0 +1,125 @@+{-# LANGUAGE OverloadedStrings     #-}+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE MultiParamTypeClasses #-}++module Text.XmlHtml.TextParser where++import           Control.Applicative+import           Data.Char+import           Data.Maybe+import           Text.XmlHtml.Common++import           Data.Text (Text)+import qualified Data.Text as T++import           Text.Parsec (Parsec)+import qualified Text.Parsec as P++import           Data.ByteString (ByteString)+import qualified Data.ByteString as B+++------------------------------------------------------------------------------+-- | Get an initial guess at document encoding from the byte order mark.  If+-- the mark doesn't exist, guess UTF-8.  Otherwise, guess according to the+-- mark.+guessEncoding :: ByteString -> (Encoding, ByteString)+guessEncoding b+    | B.take 3 b == B.pack [ 0xEF, 0xBB, 0xBF ] = (UTF8,    B.drop 3 b)+    | B.take 2 b == B.pack [ 0xFE, 0xFF ]       = (UTF16BE, B.drop 2 b)+    | B.take 2 b == B.pack [ 0xFF, 0xFE ]       = (UTF16LE, B.drop 2 b)+    | otherwise                                 = (UTF8,    b)+++------------------------------------------------------------------------------+-- | Specialized type for the parsers we use here.+type Parser = Parsec Text ()+++------------------------------------------------------------------------------+-- An (orphaned) instance for parsing Text with Parsec.+instance (Monad m) => P.Stream T.Text m Char where+    uncons = return . T.uncons+++------------------------------------------------------------------------------+parse :: (Encoding -> Parser a) -> String -> ByteString -> Either String a+parse p src b = let (e, b') = guessEncoding b+                    t       = decoder e b'+                    bad     = T.find (not . isValidChar) t+                in  if isNothing bad+                        then parseText (p e <* P.eof) src t+                        else Left $ "Document contains invalid character:"+                                 ++ " \\" ++ show (ord (fromJust bad))+++------------------------------------------------------------------------------+-- | Checks if a document contains invalid characters.+--+isValidChar :: Char -> Bool+isValidChar c | c < '\x9'                     = False+              | c > '\xA'    && c < '\xD'     = False+              | c > '\xD'    && c < '\x20'    = False+              | c > '\xD7FF' && c < '\xE000'  = False+              | c > '\xFFFD' && c < '\x10000' = False+              | otherwise                     = True+++------------------------------------------------------------------------------+-- | Parses a 'Text' value and gives back the result.  The parser is expected+-- to match the entire string.+parseText :: Parser a         -- ^ The parser to match+          -> String           -- ^ Name of the source file (can be @""@)+          -> Text             -- ^ Text to parse+          -> Either String a  -- Either an error message or the result+parseText p src t = inLeft show (P.parse p src t)+  where inLeft :: (a -> b) -> Either a c -> Either b c+        inLeft f (Left x)  = Left (f x)+        inLeft _ (Right x) = Right x+++------------------------------------------------------------------------------+-- | Consume input as long as the predicate returns 'True', and return the+-- consumed input.  This parser does not fail.  If it matches no input, it+-- will return an empty string.+takeWhile0 :: (Char -> Bool) -> Parser Text+takeWhile0 p = fmap T.pack $ P.many $ P.satisfy p+++------------------------------------------------------------------------------+-- | Consume input as long as the predicate returns 'True', and return the+-- consumed input.  This parser requires the predicate to succeed on at least+-- one character of input.  It will fail if the first character fails the+-- predicate.+takeWhile1 :: (Char -> Bool) -> Parser Text+takeWhile1 p = fmap T.pack $ P.many1 $ P.satisfy p+++------------------------------------------------------------------------------+-- | The equivalent of Parsec's string combinator, but for text.  If there is+-- not a complete match, then no input is consumed.  This matches the behavior+-- of @string@ from the attoparsec-text package.+text :: Text -> Parser Text+text t = P.try $ P.string (T.unpack t) *> return t+++------------------------------------------------------------------------------+-- | Represents the state of a text scanner, for use with the 'scanText'+-- parser combinator.+data ScanState = ScanNext (Char -> ScanState)+               | ScanFinish+               | ScanFail String+++------------------------------------------------------------------------------+-- | Scans text and progresses through a DFA, collecting the complete matching+-- text as it goes.+scanText :: (Char -> ScanState) -> Parser String+scanText f = do+    P.try $ do+        c <- P.anyChar+        case f c of+            ScanNext f'  -> (c:) `fmap` scanText f'+            ScanFinish   -> return [c]+            ScanFail err -> fail err+
+ src/Text/XmlHtml/XML/Parse.hs view
@@ -0,0 +1,600 @@+{-# LANGUAGE OverloadedStrings #-}++module Text.XmlHtml.XML.Parse where++import           Control.Applicative+import           Control.Monad+import           Data.Char+import           Data.List+import           Data.Maybe+import           Text.XmlHtml.Common+import           Text.XmlHtml.TextParser++import qualified Text.Parsec as P++import           Data.Map (Map)+import qualified Data.Map as M++import           Data.Text (Text)+import qualified Data.Text as T+++------------------------------------------------------------------------------+-- | This is my best guess as to the best rule for handling document fragments+-- for processing.  It is essentially modeled after document, but allowing+-- multiple nodes.+docFragment :: Encoding -> Parser Document+docFragment e = do+    (dt, nodes1) <- prolog+    nodes2       <- content+    return $ XmlDocument e dt (nodes1 ++ nodes2)+++-------------------------------------------------------------------------------+-- Everything from here forward is translated from the XML specification.    --+-------------------------------------------------------------------------------++{-+    Map from numbered productions in the XML specification to symbols here:++    PROD  SPEC NAME          PARSER NAME           NOTES+    -----|------------------|---------------------|-------+    [1]   document           document+    [2]   Char                                     {2}+    [3]   S                  whiteSpace+    [4]   NameStartChar      isNameStartChar       {1}+    [4a]  NameChar           isNameChar            {1}+    [5]   Name               name+    [6]   Names              names+    [7]   Nmtoken            nmtoken+    [8]   Nmtokens           nmtokens+    [9]   EntityValue                              {4}+    [10]  AttValue           attrValue+    [11]  SystemLiteral      systemLiteral+    [12]  PubidLiteral       pubIdLiteral+    [13]  PubidChar          isPubIdChar           {1}+    [14]  CharData           charData+    [15]  Comment            comment+    [16]  PI                 processingInstruction+    [17]  PITarget           piTarget+    [18]  CDSect             cdSect+    [19]  CDStart            cdSect                {3}+    [20]  CData              cdSect                {3}+    [21]  CDEnd              cdSect                {3}+    [22]  prolog             prolog+    [23]  XMLDecl            xmlDecl+    [24]  VersionInfo        versionInfo+    [25]  Eq                 eq+    [26]  VersionNum         versionInfo           {3}+    [27]  Misc               misc+    [28]  doctypedecl        docTypeDecl+    [28a] DeclSep                                  {4}+    [28b] intSubset                                {4}+    [29]  markupdecl                               {4}+    [30]  extSubset                                {4}+    [31]  extSubsetDecl                            {4}+    [32]  SDDecl             sdDecl+    [39]  element            element+    [40]  STag               emptyOrStartTag+    [41]  Attribute          attribute+    [42]  ETag               endTag+    [43]  content            content+    [44]  EmptyElemTag       emptyOrStartTag+    [45]  elementDecl                              {4}+    [46]  contentSpec                              {4}+    [47]  children                                 {4}+    [48]  cp                                       {4}+    [49]  choice                                   {4}+    [50]  seq                                      {4}+    [51]  Mixed                                    {4}+    [52]  AttlistDecl                              {4}+    [53]  AttDef                                   {4}+    [54]  AttType                                  {4}+    [55]  StringType                               {4}+    [56]  TokenizedType                            {4}+    [57]  EnumeratedType                           {4}+    [58]  NotationType                             {4}+    [59]  Enumeration                              {4}+    [60]  DefaultDecl                              {4}+    [61]  conditionalSect                          {4}+    [62]  includeSect                              {4}+    [63]  ignoreSect                               {4}+    [64]  ignoreSectContents                       {4}+    [65]  Ignore                                   {4}+    [66]  CharRef            charRef+    [67]  Reference          reference+    [68]  EntityRef          entityRef+    [69]  PEReference                              {4}+    [70]  EntityDecl                               {4}+    [71]  GEDecl                                   {4}+    [72]  PEDecl                                   {4}+    [73]  EntityDef                                {4}+    [74]  PEDef                                    {4}+    [75]  ExternalID         externalID+    [76]  NDataDecl                                {4}+    [77]  TextDecl           textDecl+    [78]  extParsedEnt       extParsedEnt+    [80]  EncodingDecl       encodingDecl+    [81]  EncName            encodingDecl          {3}+    [82]  NotationDecl                             {4}+    [83]  PublicID                                 {4}+    [84]  Letter                                   {5}+    [85]  BaseChar                                 {5}+    [86]  Ideographic                              {5}+    [87]  CombiningChar                            {5}+    [88]  Digit                                    {5}+    [89]  Extender                                 {5}++    Notes:+        {1} - These productions match single characters, and so are implemented+              as predicates instead of parsers.+        {3} - Denotes a production which is not exposed as a top-level symbol+              because it is trivial and included in another definition.+        {4} - This module does not contain a parser for the DTD subsets, so+              grammar that occurs only in DTD subsets is not defined.+        {5} - These are orphaned productions for character classes.+-}+++------------------------------------------------------------------------------+whiteSpace :: Parser ()+whiteSpace = some (P.satisfy (`elem` " \t\r\n")) *> return ()+++------------------------------------------------------------------------------+isNameStartChar :: Char -> Bool+isNameStartChar c | c == ':'                         = True+                  | c == '_'                         = True+                  | c >= 'a'       && c <= 'z'       = True+                  | c >= 'A'       && c <= 'Z'       = True+                  | c >= '\xc0'    && c <= '\xd6'    = True+                  | c >= '\xd8'    && c <= '\xf6'    = True+                  | c >= '\xf8'    && c <= '\x2ff'   = True+                  | c >= '\x370'   && c <= '\x37d'   = True+                  | c >= '\x37f'   && c <= '\x1fff'  = True+                  | c >= '\x200c'  && c <= '\x200d'  = True+                  | c >= '\x2070'  && c <= '\x218f'  = True+                  | c >= '\x2c00'  && c <= '\x2fef'  = True+                  | c >= '\x3001'  && c <= '\xd7ff'  = True+                  | c >= '\xf900'  && c <= '\xfdcf'  = True+                  | c >= '\xfdf0'  && c <= '\xfffd'  = True+                  | c >= '\x10000' && c <= '\xeffff' = True+                  | otherwise                        = False+++------------------------------------------------------------------------------+isNameChar :: Char -> Bool+isNameChar c | isNameStartChar c                = True+             | c == '-'                         = True+             | c == '.'                         = True+             | c == '\xb7'                      = True+             | c >= '0'       && c <= '9'       = True+             | c >= '\x300'   && c <= '\x36f'   = True+             | c >= '\x203f'  && c <= '\x2040'  = True+             | otherwise                        = False+++------------------------------------------------------------------------------+name :: Parser Text+name = do+    c <- P.satisfy isNameStartChar+    r <- takeWhile0 isNameChar+    return $ T.cons c r+++------------------------------------------------------------------------------+attrValue :: Parser Text+attrValue = fmap T.concat (singleQuoted <|> doubleQuoted)+  where+    singleQuoted = P.char '\'' *> refTill "<&\'" <* P.char '\''+    doubleQuoted = P.char '\"' *> refTill "<&\"" <* P.char '\"'+    refTill end = many (takeWhile1 (not . (`elem` end)) <|> reference)+++------------------------------------------------------------------------------+systemLiteral :: Parser Text+systemLiteral = singleQuoted <|> doubleQuoted+  where+    singleQuoted = do+        _ <- P.char '\''+        x <- takeWhile0 (not . (== '\''))+        _ <- P.char '\''+        return x+    doubleQuoted = do+        _ <- P.char '\"'+        x <- takeWhile0 (not . (== '\"'))+        _ <- P.char '\"'+        return x+++------------------------------------------------------------------------------+pubIdLiteral :: Parser Text+pubIdLiteral = singleQuoted <|> doubleQuoted+  where+    singleQuoted = do+        _ <- P.char '\''+        x <- takeWhile0 (\c -> isPubIdChar c && c /= '\'')+        _ <- P.char '\''+        return x+    doubleQuoted = do+        _ <- P.char '\"'+        x <- takeWhile0 isPubIdChar+        _ <- P.char '\"'+        return x+++------------------------------------------------------------------------------+isPubIdChar :: Char -> Bool+isPubIdChar c | c >= 'a' && c <= 'z'                 = True+              | c >= 'A' && c <= 'Z'                 = True+              | c >= '0' && c <= '9'                 = True+              | c `elem` " \r\n-\'()+,./:=?;!*#@$_%" = True+              | otherwise                            = False+++------------------------------------------------------------------------------+-- | The requirement to not contain "]]>" is for SGML compatibility.  We+-- deliberately choose to not enforce it.  This makes the parser accept+-- strictly more documents than a standards-compliant parser.+charData :: Parser Node+charData = TextNode <$> takeWhile1 (not . (`elem` "<&"))+++------------------------------------------------------------------------------+comment :: Parser (Maybe Node)+comment = text "<!--" *> (Just <$> Comment <$> commentText) <* text "-->"+  where+    commentText = fmap T.concat $ many $+        nonDash <|> P.try (T.cons <$> P.char '-' <*> nonDash)+    nonDash = takeWhile1 (not . (== '-'))+++------------------------------------------------------------------------------+-- | Always returns Nothing since there's no representation for a PI in the+-- document tree.+processingInstruction :: Parser (Maybe Node)+processingInstruction = do+    _ <- text "<?"+    _ <- piTarget+    _ <- emptyEnd <|> contentEnd+    return Nothing+  where+    emptyEnd   = P.try (P.string "?>")+    contentEnd = P.try $ do+        _ <- whiteSpace+        P.manyTill P.anyChar (P.try $ text "?>")++------------------------------------------------------------------------------+piTarget :: Parser ()+piTarget = do+    n <- name+    when (T.map toLower n == "xml") $ fail "xml declaration can't occur here"+++------------------------------------------------------------------------------+cdata :: [Char] -> Parser a -> Parser Node+cdata cs end = TextNode <$> T.concat <$> P.manyTill part end+  where part = takeWhile1 (not . (`elem` cs))+             <|> T.singleton <$> P.anyChar+++------------------------------------------------------------------------------+cdSect :: Parser (Maybe Node)+cdSect = Just <$> do+    _ <- text "<![CDATA["+    cdata "]" (text "]]>")+++------------------------------------------------------------------------------+prolog :: Parser (Maybe DocType, [Node])+prolog = do+    _      <- optional xmlDecl+    nodes1 <- many misc+    rest   <- optional $ do+        dt     <- docTypeDecl+        nodes2 <- many misc+        return (dt, nodes2)+    case rest of+        Nothing           -> return (Nothing, catMaybes nodes1)+        Just (dt, nodes2) -> return (Just dt, catMaybes (nodes1 ++ nodes2))+++------------------------------------------------------------------------------+-- | Return value is the encoding, if present.+xmlDecl :: Parser (Maybe Text)+xmlDecl = do+    _ <- text "<?xml"+    _ <- versionInfo+    e <- optional encodingDecl+    _ <- optional sdDecl+    _ <- optional whiteSpace+    _ <- text "?>"+    return e+++------------------------------------------------------------------------------+versionInfo :: Parser ()+versionInfo = do+    whiteSpace *> text "version" *> eq *> (singleQuoted <|> doubleQuoted)+  where+    singleQuoted = P.char '\'' *> versionNum <* P.char '\''+    doubleQuoted = P.char '\"' *> versionNum <* P.char '\"'+    versionNum   = do+        _ <- text "1."+        _ <- some (P.satisfy (\c -> c >= '0' && c <= '9'))+        return ()+++------------------------------------------------------------------------------+eq :: Parser ()+eq = optional whiteSpace *> P.char '=' *> optional whiteSpace *> return ()+++------------------------------------------------------------------------------+misc :: Parser (Maybe Node)+misc = comment <|> processingInstruction <|> (whiteSpace *> return Nothing)+++------------------------------------------------------------------------------+-- | Internal subset is parsed, but ignored since we don't have data types to+-- store it.+docTypeDecl :: Parser DocType+docTypeDecl = do+    _      <- text "<!DOCTYPE"+    whiteSpace+    tag    <- name+    _      <- optional whiteSpace+    extid  <- externalID+    _      <- optional whiteSpace+    intsub <- internalDoctype+    _      <- P.char '>'+    return (DocType tag extid intsub)+++------------------------------------------------------------------------------+-- | States for the DOCTYPE internal subset state machine.+data InternalDoctypeState = IDSStart+                          | IDSScanning Int+                          | IDSInQuote Int Char+                          | IDSCommentS1 Int+                          | IDSCommentS2 Int+                          | IDSCommentS3 Int+                          | IDSComment Int+                          | IDSCommentD1 Int+                          | IDSCommentE1 Int+++------------------------------------------------------------------------------+-- | Internal DOCTYPE subset.  We don't actually parse this; just scan through+-- and look for the end, and store it in a block of text.+internalDoctype :: Parser InternalSubset+internalDoctype = InternalText <$> T.pack <$> scanText (dfa IDSStart)+              <|> return NoInternalSubset+  where dfa IDSStart '[' = ScanNext (dfa (IDSScanning 0))+        dfa IDSStart _   = ScanFail "Not a DOCTYPE internal subset"+        dfa (IDSInQuote n c) d+          | c == d                = ScanNext (dfa (IDSScanning n))+          | otherwise             = ScanNext (dfa (IDSInQuote n c))+        dfa (IDSScanning n) '['   = ScanNext (dfa (IDSScanning (n+1)))+        dfa (IDSScanning 0) ']'   = ScanFinish+        dfa (IDSScanning n) ']'   = ScanNext (dfa (IDSScanning (n-1)))+        dfa (IDSScanning n) '\''  = ScanNext (dfa (IDSInQuote n '\''))+        dfa (IDSScanning n) '\"'  = ScanNext (dfa (IDSInQuote n '\"'))+        dfa (IDSScanning n) '<'   = ScanNext (dfa (IDSCommentS1 n))+        dfa (IDSScanning n) _     = ScanNext (dfa (IDSScanning n))+        dfa (IDSCommentS1 n) '['  = ScanNext (dfa (IDSScanning (n+1)))+        dfa (IDSCommentS1 0) ']'  = ScanFinish+        dfa (IDSCommentS1 n) ']'  = ScanNext (dfa (IDSScanning (n-1)))+        dfa (IDSCommentS1 n) '\'' = ScanNext (dfa (IDSInQuote n '\''))+        dfa (IDSCommentS1 n) '\"' = ScanNext (dfa (IDSInQuote n '\"'))+        dfa (IDSCommentS1 n) '!'  = ScanNext (dfa (IDSCommentS2 n))+        dfa (IDSCommentS1 n) _    = ScanNext (dfa (IDSScanning n))+        dfa (IDSCommentS2 n) '['  = ScanNext (dfa (IDSScanning (n+1)))+        dfa (IDSCommentS2 0) ']'  = ScanFinish+        dfa (IDSCommentS2 n) ']'  = ScanNext (dfa (IDSScanning (n-1)))+        dfa (IDSCommentS2 n) '\'' = ScanNext (dfa (IDSInQuote n '\''))+        dfa (IDSCommentS2 n) '\"' = ScanNext (dfa (IDSInQuote n '\"'))+        dfa (IDSCommentS2 n) '-'  = ScanNext (dfa (IDSCommentS3 n))+        dfa (IDSCommentS2 n) _    = ScanNext (dfa (IDSScanning n))+        dfa (IDSCommentS3 n) '['  = ScanNext (dfa (IDSScanning (n+1)))+        dfa (IDSCommentS3 0) ']'  = ScanFinish+        dfa (IDSCommentS3 n) ']'  = ScanNext (dfa (IDSScanning (n-1)))+        dfa (IDSCommentS3 n) '\'' = ScanNext (dfa (IDSInQuote n '\''))+        dfa (IDSCommentS3 n) '\"' = ScanNext (dfa (IDSInQuote n '\"'))+        dfa (IDSCommentS3 n) '-'  = ScanNext (dfa (IDSComment n))+        dfa (IDSCommentS3 n) _    = ScanNext (dfa (IDSScanning n))+        dfa (IDSComment n) '-'    = ScanNext (dfa (IDSCommentD1 n))+        dfa (IDSComment n) _      = ScanNext (dfa (IDSComment n))+        dfa (IDSCommentD1 n) '-'  = ScanNext (dfa (IDSCommentE1 n))+        dfa (IDSCommentD1 n) _    = ScanNext (dfa (IDSComment n))+        dfa (IDSCommentE1 n) '>'  = ScanNext (dfa (IDSScanning n))+        dfa (IDSCommentE1 _) _    = ScanFail "Poorly formatted comment"+++------------------------------------------------------------------------------+sdDecl :: Parser ()+sdDecl = do+    _ <- P.try $ whiteSpace *> text "standalone"+    eq+    _ <- single <|> double+    return ()+  where+    single = P.char '\'' *> yesno <* P.char '\''+    double = P.char '\"' *> yesno <* P.char '\"'+    yesno  = text "yes" <|> text "no"+++------------------------------------------------------------------------------+element :: Parser Node+element = do+    (t,a,b) <- emptyOrStartTag+    if b then return (Element t a [])+         else nonEmptyElem t a+  where+    nonEmptyElem t a = do+        c <- content+        endTag t+        return (Element t a c)+++------------------------------------------------------------------------------+-- | Results are (tag name, attributes, isEmpty)+emptyOrStartTag :: Parser (Text, [(Text, Text)], Bool)+emptyOrStartTag = do+    t <- P.try $ P.char '<' *> name+    a <- many $ P.try $ do+        whiteSpace+        attribute+    when (hasDups a) $ fail "Duplicate attribute names in element"+    _ <- optional whiteSpace+    e <- optional (P.char '/')+    _ <- P.char '>'+    return (t, a, isJust e)+  where+    hasDups a = length (nub (map fst a)) < length a+++------------------------------------------------------------------------------+attribute :: Parser (Text, Text)+attribute = do+    n <- name+    eq+    v <- attrValue+    return (n,v)+++------------------------------------------------------------------------------+endTag :: Text -> Parser ()+endTag s = do+    _ <- text "</"+    t <- name+    when (s /= t) $ fail $ "mismatched tags: </" ++ T.unpack t +++                           "> found inside <" ++ T.unpack s ++ "> tag"+    _ <- optional whiteSpace+    _ <- text ">"+    return ()+++------------------------------------------------------------------------------+content :: Parser [Node]+content = do+    n  <- optional charData+    ns <- fmap concat $ many $ do+        s <- ((Just <$> TextNode <$> reference)+               <|> cdSect+               <|> processingInstruction+               <|> comment+               <|> fmap Just element)+        t <- optional charData+        return [s,t]+    return $ coalesceText $ catMaybes (n:ns)+  where+    coalesceText (TextNode s : TextNode t : ns)+        = coalesceText (TextNode (T.append s t) : ns)+    coalesceText (n:ns)+        = n : coalesceText ns+    coalesceText []+        = []+++------------------------------------------------------------------------------+charRef :: Parser Text+charRef = hexCharRef <|> decCharRef+  where+    decCharRef = do+        _ <- text "&#"+        ds <- some digit+        _ <- P.char ';'+        let c = chr $ foldl' (\a b -> 10 * a + b) 0 ds+        when (not (isValidChar c)) $ fail $+            "Reference is not a valid character"+        return $ T.singleton c+      where+        digit = do+            d <- P.satisfy (\c -> c >= '0' && c <= '9')+            return (ord d - ord '0')+    hexCharRef = do+        _ <- text "&#x"+        ds <- some digit+        _ <- P.char ';'+        let c = chr $ foldl' (\a b -> 16 * a + b) 0 ds+        when (not (isValidChar c)) $ fail $+            "Reference is not a valid character"+        return $ T.singleton c+      where+        digit = num <|> upper <|> lower+        num = do+            d <- P.satisfy (\c -> c >= '0' && c <= '9')+            return (ord d - ord '0')+        upper = do+            d <- P.satisfy (\c -> c >= 'A' && c <= 'F')+            return (10 + ord d - ord 'A')+        lower = do+            d <- P.satisfy (\c -> c >= 'a' && c <= 'f')+            return (10 + ord d - ord 'a')+++------------------------------------------------------------------------------+reference :: Parser Text+reference = charRef <|> entityRef+++------------------------------------------------------------------------------+entityRef :: Parser Text+entityRef = do+    _ <- P.char '&'+    n <- name+    _ <- P.char ';'+    case M.lookup n entityRefLookup of+        Nothing -> fail $ "Unknown entity reference: " ++ T.unpack n+        Just t  -> return t+  where+    entityRefLookup :: Map Text Text+    entityRefLookup = M.fromList [+        ("amp", "&"),+        ("lt", "<"),+        ("gt", ">"),+        ("apos", "\'"),+        ("quot", "\"")+        ]+++------------------------------------------------------------------------------+externalID :: Parser ExternalID+externalID = systemID <|> publicID <|> return NoExternalID+  where+    systemID = do+        _ <- text "SYSTEM"+        whiteSpace+        fmap System systemLiteral+    publicID = do+        _ <- text "PUBLIC"+        whiteSpace+        pid <- pubIdLiteral+        whiteSpace+        sid <- systemLiteral+        return (Public pid sid)+++------------------------------------------------------------------------------+encodingDecl :: Parser Text+encodingDecl = do+    _ <- P.try $ whiteSpace *> text "encoding"+    _ <- eq+    singleQuoted <|> doubleQuoted+  where+    singleQuoted = P.char '\'' *> encName <* P.char '\''+    doubleQuoted = P.char '\"' *> encName <* P.char '\"'+    encName      = do+        c  <- P.satisfy isEncStart+        cs <- takeWhile0 isEnc+        return (T.cons c cs)+    isEncStart c | c >= 'A' && c <= 'Z' = True+                 | c >= 'a' && c <= 'z' = True+                 | otherwise = False+    isEnc      c | c >= 'A' && c <= 'Z' = True+                 | c >= 'a' && c <= 'z' = True+                 | c >= '0' && c <= '9' = True+                 | c `elem` "._-"       = True+                 | otherwise = False+
+ src/Text/XmlHtml/XML/Render.hs view
@@ -0,0 +1,153 @@+{-# LANGUAGE OverloadedStrings #-}++module Text.XmlHtml.XML.Render where++import           Blaze.ByteString.Builder+import           Data.Char+import           Data.Maybe+import           Data.Monoid+import           Text.XmlHtml.Common++import           Data.Text (Text)+import qualified Data.Text as T+++------------------------------------------------------------------------------+render :: Encoding -> Maybe DocType -> [Node] -> Builder+render e dt ns = byteOrder+       `mappend` xmlDecl e+       `mappend` docTypeDecl e dt+       `mappend` nodes+    where byteOrder | isUTF16 e = fromText e "\xFEFF" -- byte order mark+                    | otherwise = mempty+          nodes | null ns   = mempty+                | otherwise = firstNode e (head ns)+                    `mappend` (mconcat $ map (node e) (tail ns))+++------------------------------------------------------------------------------+xmlDecl :: Encoding -> Builder+xmlDecl e = fromText e "<?xml version=\"1.0\" encoding=\""+            `mappend` fromText e (encodingName e)+            `mappend` fromText e "\"?>\n"+++------------------------------------------------------------------------------+docTypeDecl :: Encoding -> Maybe DocType -> Builder+docTypeDecl _ Nothing                      = mempty+docTypeDecl e (Just (DocType tag ext int)) = fromText e "<!DOCTYPE "+                                   `mappend` fromText e tag+                                   `mappend` externalID e ext+                                   `mappend` internalSubset e int+                                   `mappend` fromText e ">"+++------------------------------------------------------------------------------+externalID :: Encoding -> ExternalID -> Builder+externalID _ NoExternalID     = mempty+externalID e (System sid)     = fromText e " SYSTEM "+                                `mappend` sysID e sid+externalID e (Public pid sid) = fromText e " PUBLIC "+                                `mappend` pubID e pid+                                `mappend` fromText e " "+                                `mappend` sysID e sid+++------------------------------------------------------------------------------+internalSubset :: Encoding -> InternalSubset -> Builder+internalSubset _ NoInternalSubset = mempty+internalSubset e (InternalText t) = fromText e " " `mappend` fromText e t+++------------------------------------------------------------------------------+sysID :: Encoding -> Text -> Builder+sysID e sid | not ("\'" `T.isInfixOf` sid) = fromText e "\'"+                                             `mappend` fromText e sid+                                             `mappend` fromText e "\'"+            | not ("\"" `T.isInfixOf` sid) = fromText e "\""+                                             `mappend` fromText e sid+                                             `mappend` fromText e "\""+            | otherwise               = error "SYSTEM id is invalid"+++------------------------------------------------------------------------------+pubID :: Encoding -> Text -> Builder+pubID e sid | not ("\"" `T.isInfixOf` sid) = fromText e "\""+                                             `mappend` fromText e sid+                                             `mappend` fromText e "\""+            | otherwise               = error "PUBLIC id is invalid"+++------------------------------------------------------------------------------+node :: Encoding -> Node -> Builder+node e (TextNode t)                        = escaped "<>&" e t+node e (Comment t) | "--" `T.isInfixOf` t  = error "Invalid comment"+                   | "-" `T.isSuffixOf` t  = error "Invalid comment"+                   | otherwise             = fromText e "<!--"+                                             `mappend` fromText e t+                                             `mappend` fromText e "-->"+node e (Element t a c)                     = element e t a c+++------------------------------------------------------------------------------+-- | Process the first node differently to encode leading whitespace.  This+-- lets us be sure that @parseXML@ is a left inverse to @render@.+firstNode :: Encoding -> Node -> Builder+firstNode e (Comment t)     = node e (Comment t)+firstNode e (Element t a c) = node e (Element t a c)+firstNode _ (TextNode "")   = mempty+firstNode e (TextNode t)    = let (c,t') = fromJust $ T.uncons t+                              in escaped "<>& \t\r\n" e (T.singleton c)+                                 `mappend` node e (TextNode t')+++------------------------------------------------------------------------------+escaped :: [Char] -> Encoding -> Text -> Builder+escaped _   _ "" = mempty+escaped bad e t  = let (p,s) = T.break (`elem` bad) t+                       r     = T.uncons s+                   in  fromText e p `mappend` case r of+                         Nothing     -> mempty+                         Just (c,ss) -> entity e c `mappend` escaped bad e ss+++------------------------------------------------------------------------------+entity :: Encoding -> Char -> Builder+entity e '&'  = fromText e "&amp;"+entity e '<'  = fromText e "&lt;"+entity e '>'  = fromText e "&gt;"+entity e '\"' = fromText e "&quot;"+entity e c    = fromText e "&#"+                `mappend` fromText e (T.pack (show (ord c)))+                `mappend` fromText e ";"+++------------------------------------------------------------------------------+element :: Encoding -> Text -> [(Text, Text)] -> [Node] -> Builder+element e t a [] = fromText e "<"+        `mappend` fromText e t+        `mappend` (mconcat $ map (attribute e) a)+        `mappend` fromText e "/>"+element e t a c = fromText e "<"+        `mappend` fromText e t+        `mappend` (mconcat $ map (attribute e) a)+        `mappend` fromText e ">"+        `mappend` (mconcat $ map (node e) c)+        `mappend` fromText e "</"+        `mappend` fromText e t+        `mappend` fromText e ">"+++------------------------------------------------------------------------------+attribute :: Encoding -> (Text, Text) -> Builder+attribute e (n,v) | not ("\'" `T.isInfixOf` v) = fromText e " "+                                       `mappend` fromText e n+                                       `mappend` fromText e "=\'"+                                       `mappend` escaped "<&" e v+                                       `mappend` fromText e "\'"+                  | otherwise                  = fromText e " "+                                       `mappend` fromText e n+                                       `mappend` fromText e "=\""+                                       `mappend` escaped "<&\"" e v+                                       `mappend` fromText e "\""+
+ xmlhtml.cabal view
@@ -0,0 +1,51 @@+Name:                xmlhtml+Version:             0.1+Synopsis:            XML parser and renderer with HTML 5 quirks mode+Description:         Contains renderers and parsers for both XML and HTML 5+                     document fragments, which share data structures wo that+                     it's easy to work with both.  Document fragments are bits+                     of documents, which are not constrained by some of the+                     high-level structure rules (in particular, they may+                     contain more than one root element).+                     .+                     Note that this is not a compliant HTML 5 parser.  Rather,+                     it is a parser for HTML 5 compliant documents.  It does not+                     implement the HTML 5 parsing algorithm, and should+                     generally be expected to perform correctly only on+                     documents that you trust to conform to HTML 5.  This is+                     not a suitable library for implementing web crawlers or+                     other software that will be exposed to documents from+                     outside sources.  The result is also not the HTML 5+                     node structure, but rather something closer to the physical+                     structure.  For example, omitted start tags are not+                     inserted (and so, their corresponding end tags must also be+                     omitted).+License:             BSD3+License-file:        LICENSE+Author:              Chris Smith <cdsmith@gmail.com>+Maintainer:          Chris Smith <cdsmith@gmail.com>+Category:            Text+Build-type:          Simple+Cabal-version:       >=1.6++Library+  Hs-source-dirs:      src+  Exposed-modules:     Text.XmlHtml,+                       Text.XmlHtml.Cursor,+                       Text.Blaze.Renderer.XmlHtml+  Other-modules:       Text.XmlHtml.Common,+                       Text.XmlHtml.TextParser,+                       Text.XmlHtml.XML.Parse,+                       Text.XmlHtml.XML.Render,+                       Text.XmlHtml.HTML.Meta,+                       Text.XmlHtml.HTML.Parse,+                       Text.XmlHtml.HTML.Render+  Build-depends:       base == 4.*,+                       blaze-builder == 0.2.*,+                       blaze-html == 0.3.*,+                       bytestring == 0.9.*,+                       containers >= 0.3 && <0.5,+                       parsec >= 3.0 && < 3.2,+                       text >= 0.11 && < 0.12++  Ghc-options:         -Wall -fwarn-tabs