如何编写带有特殊字符的 xml 代码(使用 R xml 包)

How to write xml code (using R xml package) with special characters

我正在尝试编写特定程序需要的一些 xml 文件,但在某些文本中写入 'special characters' 时遇到问题,因此程序抛出错误。

如何将特殊字符(特别是“>”)写入标签的属性?

library(XML) 

xml <- xmlTree()
  xml$addTag("events", close=FALSE, attrs = c(PackageMinimumVersionRequired="1.3") )  
  
  # '>' is a special character that gets rewritten as '&gt;'
    xml$addTag("schedule", close=TRUE, 
                attrs = c(time = paste("2000-01-01/1 -> +6-0-0", sep='') ) )
xml$addTag('party', close=FALSE, attrs = c(number='1')) #just putting this in to show I have other nodes
xml$closeTag() # close party 
xml$closeTag() # close events
    
saveXML(xml, file = "testfile.xml", encoding = "UTF-8" )  
  

'time' 属性写为:time="2000-01-01/1 - >; +6-0-0"

我认为应该使用这些方法,但还没有找到解决方法...

xmlCDataNode()
# or 
xml$addCData 

次要问题 - 如何为每个标签缩进一个新行?
xml header 有自己的行,但除此之外,所有标签都水平堆叠在同一行中。我希望每个新标签都换行(我正在使用记事本++或其他编辑器查看代码)。

某些字符,特别是 <&,必须始终进行转义。如果您的库没有转义这些字符,输出将不会是格式正确的 XML 并且将无法使用。

其他字符,如>"',需要在特定条件下转义,许多库会无条件转义它们,因为这是最简单的事情做,一旦你把 XML 通过解析器,它就没有任何区别了。如果你真的希望 > 不被转义,你应该问问自己为什么。仅仅是出于审美原因吗?如果下游软件依赖于它未被转义,那么下游软件就是有问题的 - 并且编写 XML 可以被有问题的客户端消耗,这会导致大量的 Whosebug 流量,所以你手上有问题。

我被要求解决这个问题,因为我是 XML 包的作者。 正如迈克尔所说,如果属性是

time = "2000-01-01/1 -> +6-0-0"

虽然 xmlParse() 和 libxml2 会正确地解析它并将 > 转换为 >,但它的格式是错误的 XML字符序列。

有趣的是,> 字符没有转换为 >当我们创建属性时:

z = newXMLNode("bob", attrs = c(a = "x > y"))
xmlGetAttr(z, "a")
[1] "x > y"

转换发生在对 saveXML() 的调用中。因此,原则上,您可以避免 saveXML() 并编写 R 代码来遍历树并自己生成输出,以您想要的方式处理每个属性。但是,这是最后的手段。

尽管我讨厌使用正则表达式来处理 XML,但我建议您 post- 处理 saveXML() 的输出,如果您的内容是“制服”,全部替换 >带有 >,即

cat(gsub("&gt;", ">", saveXML(xml$value())))

<?xml version="1.0"?>
<events PackageMinimumVersionRequired="1.3">
  <schedule time="2000-01-01/1 -> +6-0-0"/>
  <party number="1"/>
</events>

如果可以替换all>就比较简单了与>。如果您需要更换 >对于某些上下文中出现的部分子集,您的正则表达式必须更复杂。

Q2 要在单独的行上获取节点并缩进,请使用

saveXML(xml$value(), "testfile.xml", encoding = "UTF-8")

即通过调用 xml$value() 获取文档对象并保存。

顺便说一句,我倾向于不使用 xmlTree() 及其函数集合(例如添加和关闭),而是

doc = newXMLDoc()
e = newXMLNode("events", attrs = c(PackageMinimumVersionRequired="1.3") , doc = doc)
newXMLNode("schedule", attrs = c(time = paste("2000-01-01/1 -> +6-0-0", sep='')), parent = e)

您甚至可以选择删除 doc 部分。