使用R修改XML节点顺序(或将新节点添加到特定位置)

时间:2015-11-02 12:53:05

标签: xml r

我知道这可能是最容易使用XSL的,但我需要在R中执行。我有以下类型的XML文件:

||

如果我需要添加一个新节点,我会这样做:

<xml>
  <info>Some info here</info>
  <node id='1'/>
  <node id='2'/>
  <node id='3'/>
  <comment>Some comment here</comment>
</xml>

但是,这会将新节点添加到文档的末尾,如下所示:

library(XML)

xml <- "<xml><info>Some info here</info><node id='1'/><node id='2'/><node id='3'/><comment>Some comment here</comment></xml>"

doc <- xmlParse(xml)

doc <- getNodeSet(doc, "//xml")

new_node <- newXMLNode("node", attrs = c(id = 4))

# Is there a way to specify here where to insert the node?

doc <- addChildren(doc[[1]], new_node)

# Or can one sort it somehow once it is there?

我需要维护原始结构,其中包含特定顺序的元素。为了清楚起见,这就是我需要的:

<xml>
  <info>Some info here</info>
  <node id="1"/>
  <node id="2"/>
  <node id="3"/>
  <comment>Some comment here</comment>
  <node id="4"/>
</xml> 

当我试图在标题中解释时,我认为这个问题有两个解决方案。一种方法是在最后<xml> <info>Some info here</info> <node id="1"/> <node id="2"/> <node id="3"/> <node id="4"/> <comment>Some comment here</comment> </xml> <node>之间添加新节点。或者在将其插入到最后之后指定正确的顺序并使用该顺序对文档进行排序。

2 个答案:

答案 0 :(得分:1)

您可以使用xmlChildren<-并通过标准R子集重新排序元素:

xml <- "<xml><info>Some info here</info><node id='1'/><node id='2'/><node id='3'/><comment>Some comment here</comment></xml>"
doc <- xmlParse(xml)
doc <- getNodeSet(doc, "//xml")
new_node <- newXMLNode("node", attrs = c(id = 4))
xmlChildren(doc[[1]])<-c(xmlChildren(doc[[1]]),node=new_node)[c(1:4,6,5)]
doc[[1]]
#<xml>
#   <info>Some info here</info> 
#   <node id="1"/>
#   <node id="2"/>
#   <node id="3"/>
#   <node id="4"/>
#   <comment>Some comment here</comment>
#</xml> 

答案 1 :(得分:1)

这是R中的XSLT解决方案,以防您的修改变得更加复杂(或定制)以及未来的读者。因为R还没有通用的XSLT库,所以它可以通过RCOMClient或命令行使用已安装的XSLT处理器。由于大多数通用语言都支持XSLT库(Java,C#,PHP,Perl,Python,VB),因此R可以相应地利用它们。

以下示例是VBA和Python方法。 VBA使用Microsoft Office安装附带的MSXML对象。此外,开源Python使用其lxml模块通过命令行运行。

R 使用RDCOMClient,假设您在PC上安装了Microsoft Office;可以轻松翻译为Excel宏

library(XML)
library(RDCOMClient)

# ADD NEEDED NODE(S)
xml <- "<xml><info>Some info here</info><node id='1'/><node id='2'/><node id='3'/><comment>Some comment here</comment></xml>"
doc <- xmlParse(xml)
doc <- getNodeSet(doc, "//xml")
new_node <- newXMLNode("node", attrs = c(id = 4))
doc <- addChildren(doc[[1]], new_node)
xmlstr <- saveXML(xmlstr)

# INITIALIZE MSXML OBJECTS
xmlfile = COMCreate("MSXML2.DOMDocument")
xslfile = COMCreate("MSXML2.DOMDocument")
newxmlfile = COMCreate("MSXML2.DOMDocument")

# XSLT TRANSFORMATION
xslstr = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>
  <xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">
  <xsl:output omit-xml-declaration=\"yes\" indent=\"yes\"/>
  <xsl:strip-space elements=\"*\"/>

  <xsl:template match=\"xml\">
  <xml>
    <xsl:copy-of select=\"info\"/>  
    <xsl:copy-of select=\"node\"/>
    <xsl:copy-of select=\"comment\"/>
  </xml>
  </xsl:template>  
  </xsl:stylesheet>"

newxmlstr = "Output_R.xml"

# LOADING XML & XSLT FILES
xmlfile.async = FALSE
xmlfile$LoadXML(xmlstr)

xslfile.async = FALSE
xslfile$LoadXML(xslstr)

# TRANSFORMING XML FILE USING XLST INTO NEW FILE
xmlfile$transformNodeToObject(xslfile, newxmlfile)
newxmlfile$Save(newxmlstr)

# SHOW OUTPUT
doc<-xmlParse(newxmlstr)
doc

# UNINITIALIZE MSXML OBJECTS
xmlfile <- NULL
xslfile <- NULL
newxmlfile <- NULL

R 通过命令行在Python脚本下面调用,假设&#39; python&#39;是PC机的PATH中的环境变量

library(XML)

# ADD NEEDED NODE(S)
xml <- "<xml><info>Some info here</info><node id='1'/><node id='2'/><node id='3'/><comment>Some comment here</comment></xml>"
doc <- xmlParse(xml)
doc <- getNodeSet(doc, "//xml")
new_node <- newXMLNode("node", attrs = c(id = 4))
doc <- addChildren(doc[[1]], new_node)
out <- saveXML(doc, file="NewNode.xml")

# COMMAND LINE CALL
shell(paste("python", shQuote("C:\\Path\\To\\PythonScript.py")))

Python (从文件解析从R输出的XML并将结果xml输出到文件)

import os
import lxml.etree as ET

cd = os.path.dirname(os.path.abspath(__file__))

xsl ="<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\
      <xsl:output omit-xml-declaration=\"yes\" indent=\"yes\"/>\
      <xsl:strip-space elements=\"*\"/>\
      <xsl:template match=\"xml\">\
        <xml>\
          <xsl:copy-of select=\"info\"/> \
          <xsl:copy-of select=\"node\"/> \
          <xsl:copy-of select=\"comment\"/> \
        </xml>\
      </xsl:template>\
      </xsl:stylesheet>"""

# PARSING XML AND XSL    
dom = ET.parse(os.path.join(cd,'NewNode.xml'))
xslobj = ET.fromstring(xsl)
transform = ET.XSLT(xslobj)
newdom = transform(dom)

# OUTPUT TO FILE
tree_out = ET.tostring(newdom, encoding='UTF-8', pretty_print=True,  xml_declaration=True)
# SHOW OUTPUT
print(tree_out)

xmlfile = open(os.path.join(cd, 'Output_py.xml'),'wb')
xmlfile.write(tree_out)
xmlfile.close()

最终输出 (两种方法)

<?xml version="1.0"?>
<xml>
  <info>Some info here</info>
  <node id="1"/>
  <node id="2"/>
  <node id="3"/>
  <node id="4"/>
  <comment>Some comment here</comment>
</xml>

虽然上述所有内容看起来都很复杂,但请记住,编程语言是做特殊事情的工具,包括通用(Java,C,Python)和专用(SQL,XSLT)语言。 R实际上是一种统计计算语言,可能不是解析和转换XML文档的最佳工具。一个好的勤杂工不会用锤子做每一份工作!