使用HXT操作XML

时间:2014-11-05 22:21:58

标签: xml haskell refactoring hxt

据我所知,正常的HXT似乎更倾向于XML的查询,而不是XML AST重构。然而,其中一个HXT模块,Data.Tree.NTree.Zippers.TypeDefs似乎有一些机制可以潜入文档并进行本地工作,而不是更全局的箭头。但是,我似乎无法得到任何工作。这是my earlier HXT issue的后续帖子 - 所有代码都相同,但现在trans正在替换this

以下是我的计划的切入点:

start :: App -> IO [XmlTree]
start (App src dest) = runX $
                         readDocument [
                                    --... some settings ...
                                      ]   
                                      src
                         >>>
                         trans
                         >>> 
                         writeDocument [
                                     --... some settings ...
                                       ]
                                       dest

以下是定义trans的模块:

module Main.Internal where

import Data.Maybe (fromJust)

import Text.XML.HXT.DOM.XmlNode (mkText')
import Text.XML.HXT.Core hiding (addToTheRight)
import Data.Tree.NTree.Zipper.TypeDefs

trans :: IOSLA (XIOState s) XmlTree XmlTree
trans = arrL go
  where
    go :: XmlTree -> [XmlTree]
    go x = [fromNTZipper . manip . toNTZipper $ x]

unList :: [a] -> a
unList []    = error "dun goofed!"
unList (x:_) = x

manip = fromJust . (addToTheRight $ mkText' "bar")
      . fromJust . down

最后,这是我的输入文件:

<html>
  <head>
    <title>foo</title>
  </head>
  <body>
    <h1>foo</h1>
  </body>
</html>

和我的输出:

<?xml version="1.0" encoding="US-ASCII"?>
<html>
  <head>
    <title>foo</title>
  </head>
  <body>
    <h1>foo</h1>
  </body>
</html>

那么,为什么在我的输出中找不到“bar”?它不应该出现在</html>之后吗?任何帮助都会很棒:)

1 个答案:

答案 0 :(得分:1)

您的想法似乎很可靠,而且我不确定您的错误在哪里,但在玩弄它我能够生成测试代码:

import Data.Tree.NTree.Zipper.TypeDefs
import Text.XML.HXT.Parser.HtmlParsec
import Text.XML.HXT.DOM.XmlNode
import Text.XML.HXT.DOM.TypeDefs
import Data.Tree.NTree.TypeDefs
import Control.Arrow.IOListArrow
import Text.XML.HXT.Arrow.WriteDocument
str = "<html>\n  <head>\n    <title>foo</title>\n  </head>\n  <body>\n    <h1>foo</h1>\n  </body>\n</html>"

fromJust (Just x) = x

manip :: NTree XNode -> NTree XNode
manip x = fromNTZipper $ fromJust $
        down (toNTZipper x) >>= addToTheLeft (mkText "Boo!") >>= up

stringify = runIOLA $ writeDocumentToString []

main = do
    xs <- mapM stringify $ map manip $ parseHtmlDocument "" str
    putStrLn (show xs)

输出[["\n Boo!<head>\n <title>foo</title>\n </head>\n <body>\n <h1>foo</h1>\n </body>\n"]]。我实际上并不确定<html>元素发生了什么,但addToTheLeft完全按照它所说的做了。 (我正在使用>>=上面的Maybe monad。

我不知道它是trans还是>>>,但你正在做的manip似乎应该有效。< / p>

编辑:请注意,我上面写的很多内容避免了那些对HXT至关重要的惯用箭头,这可能就是我为什么会这样做的原因。得到一些奇怪的结果。从包结构看,导入Text.XML.HXT.Core足以通常读取字符串和文档。以下适用于我:

Prelude> let file = "<html>\n  <head>\n    <title>foo</title>\n  </head>\n  <body>\n    <h1>foo</h1>\n  </body>\n</html>"
Prelude> :m +Text.XML.HXT.Core
Prelude Text.XML.HXT.Core> let apply (arrows) str = head $ runLA (xshow $ hread >>> arrows) str
Prelude Text.XML.HXT.Core> :t apply
apply :: LA XmlTree XmlTree -> String -> String
Prelude Text.XML.HXT.Core> putStrLn $ apply (withNav $ moveDown >>> addToTheLeft (txt "bar") >>> moveUp) file
<html>bar
  <head>
    <title>foo</title>
  </head>
  <body>
    <h1>foo</h1>
  </body>
</html>

所以那些是相关的功能。请注意,HXT似乎已经通过破坏列表(Maybe列表箭头中)不满足给定谓词的XML树来执行其LA内容。