复制一个 XML 文件,保留一些元素的结束标签

Copy an XML file preserving closing tags of some elements

我正在破解一个应该复制 XML 文件并编辑其中一小部分的东西 它。现在编辑没问题,但有趣的是复制可能相当 棘手的。这本质上是“逆向工程”工作,现在我知道我 应该以某种方式保留某些元素的结束标记(即使元素 仅包含白色 space 或为空)。问题是当 HXT 读取 像

<tag>
</tag>

然后将其打印为

<tag/>

我可以告诉它始终使用显式结束标记(或任何您称之为的标记) 但是,为 writeDocument 函数指定 withOutputXHTML 选项 有写成

的元素
<tag/>

应按原样复制。

所以,基本上我的问题归结为:«如何复制此文件以保留 某些特定元素的结束标记?»:

<foo>
  <bar>
  </bar>
  <baz/>
</foo>

reference/experiment的简单复制程序:

module Main (main) where

import Control.Monad (void)
import Text.XML.HXT.Core

main :: IO ()
main = void $ runX $
       readDocument [ withValidate no ] "test.xml" >>>
       writeDocument [ withIndent yes
                     , withOutputEncoding isoLatin1
                     , withOutputXHTML ] "result.xml"

经过漫长而令人沮丧的搜索,我决定尝试所有选项 Text.XML.HXT.Arrow.XmlState。 有些选项没有文档字符串,所以这是一个猜谜游戏。

终于,我发现了这个奇迹:

withNoEmptyElemFor :: [String] -> SysConfig

虽然它没有文档字符串,但它的名字听起来很有前途。的确,与 在这个选项的帮助下,我们可以指定 «cannot be 空».

这个选项可以与 writeDocument 要么 configSysVars。 我更喜欢第二个箭头,因为我可以在本地使用它,如果 你有几个箭头执行略有不同的处理 可能有不同标签集合的文档,这些标签不应该 空(这是我的情况)。

所以,回到我的例子,我们可以通过写来修复它:

module Main (main) where

import Control.Monad (void)
import Text.XML.HXT.Core

main :: IO ()
main = void $ runX $
       readDocument [ withValidate no ] "test.xml" >>>
       writeDocument [ withIndent yes
                     , withOutputEncoding isoLatin1
                     , withNoEmptyElemFor ["bar"] ] "result.xml"

万一有用,保留空格是 xml-conduit 的默认行为。以下不会折叠您的 <tag> 元素,例如:

{-# LANGUAGE OverloadedStrings #-}
import qualified Text.XML as X

main :: IO ()
main = do
    doc <- X.readFile X.def "foo.xml"
    X.writeFile X.def "bar.xml" doc