File: XMLUtils.hs

package info (click to toggle)
haskell-haskell-gi 0.26.12-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 800 kB
  • sloc: haskell: 8,617; ansic: 74; makefile: 4
file content (95 lines) | stat: -rw-r--r-- 3,578 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
-- | Some helpers for making traversals of GIR documents easier.
module Data.GI.GIR.XMLUtils
    ( nodeToElement
    , subelements
    , localName
    , lookupAttr
    , GIRXMLNamespace(..)
    , lookupAttrWithNamespace
    , childElemsWithLocalName
    , childElemsWithNSName
    , firstChildWithLocalName
    , getElementContent
    , xmlLocalName
    , xmlNSName
    ) where

import Text.XML (Element(elementNodes, elementName, elementAttributes),
                 Node(NodeContent, NodeElement), nameLocalName, Name(..))
import Data.Maybe (mapMaybe, listToMaybe)
import qualified Data.Map as M
import Data.Text (Text)

-- | Turn a node into an element (if it is indeed an element node).
nodeToElement :: Node -> Maybe Element
nodeToElement (NodeElement e) = Just e
nodeToElement _               = Nothing

-- | Find all children of the given element which are XML Elements
-- themselves.
subelements :: Element -> [Element]
subelements = mapMaybe nodeToElement . elementNodes

-- | The local name of an element.
localName :: Element -> Text
localName = nameLocalName . elementName

-- | Restrict to those with the given local name.
childElemsWithLocalName :: Text -> Element -> [Element]
childElemsWithLocalName n =
    filter localNameMatch . subelements
    where localNameMatch = (== n) . localName

-- | Restrict to those with given name.
childElemsWithNSName :: GIRXMLNamespace -> Text -> Element -> [Element]
childElemsWithNSName ns n = filter nameMatch . subelements
    where nameMatch = (== name) . elementName
          name = Name {
                   nameLocalName = n
                 , nameNamespace = Just (girNamespace ns)
                 , namePrefix = Nothing
                 }

-- | Find the first child element with the given name.
firstChildWithLocalName :: Text -> Element -> Maybe Element
firstChildWithLocalName n = listToMaybe . childElemsWithLocalName n

-- | Get the content of a given element, if it exists.
getElementContent :: Element -> Maybe Text
getElementContent = listToMaybe . mapMaybe getContent . elementNodes
    where getContent :: Node -> Maybe Text
          getContent (NodeContent t) = Just t
          getContent _ = Nothing

-- | Lookup an attribute for an element (with no prefix).
lookupAttr :: Name -> Element -> Maybe Text
lookupAttr attr element = M.lookup attr (elementAttributes element)

-- | GIR namespaces we know about.
data GIRXMLNamespace = GLibGIRNS | CGIRNS | CoreGIRNS
                     deriving Show

-- | Return the text representation of the known GIR namespaces.
girNamespace :: GIRXMLNamespace -> Text
girNamespace GLibGIRNS = "http://www.gtk.org/introspection/glib/1.0"
girNamespace CGIRNS = "http://www.gtk.org/introspection/c/1.0"
girNamespace CoreGIRNS = "http://www.gtk.org/introspection/core/1.0"

-- | Lookup an attribute for an element, given the namespace where it lives.
lookupAttrWithNamespace :: GIRXMLNamespace -> Name -> Element -> Maybe Text
lookupAttrWithNamespace ns attr element =
    let attr' = attr {nameNamespace = Just (girNamespace ns)}
    in M.lookup attr' (elementAttributes element)


-- | Construct a `Text.XML.Name` by only giving the local name.
xmlLocalName :: Text -> Name
xmlLocalName n = Name { nameLocalName = n
                      , nameNamespace = Nothing
                      , namePrefix = Nothing }

-- | Construct a `Text.XML.Name` specifying a namespace too.
xmlNSName :: GIRXMLNamespace -> Text -> Name
xmlNSName ns n = Name { nameLocalName = n
                      , nameNamespace = Just (girNamespace ns)
                      , namePrefix = Nothing }