通过 Xpaths 从 R 中的文件中删除或过滤 XML 节点

Posted

技术标签:

【中文标题】通过 Xpaths 从 R 中的文件中删除或过滤 XML 节点【英文标题】:Remove or filter XML nodes by Xpaths from file in R 【发布时间】:2021-11-04 11:59:11 【问题描述】:

我有非常大的复杂 xml 文件(看起来像 https://github.com/HL7/C-CDA-Examples/blob/master/General/Parent%20Document%20Replace%20Relationship/CCD%20Parent%20Document%20Replace%20(C-CDAR2.1).xml)要处理,但只需要特定 XPath(节点)的属性和值。通过去除不需要的节点,可以缩短处理时间,在详细处理之前过滤掉绒毛。

到目前为止,我已经尝试过使用:xml_remove

xmlfile <- paste0(dir,"xmlFiles/",filelist[k])
file<-read_xml(xmlfile)
file<-xml_ns_strip(file)

for(counx in 1:nrow(xpathTable))   
        xr <- xml_find_all(file, xpath =paste0('/',toString(xpathTable$xpaths[counx])) )
        xml_remove(xr, free = TRUE)
        file<-file              
    

这适用于删除少数节点,但随着数量的增加 (>100) 会崩溃

下面显示一个我也想得到的例子

<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
    <book category="cooking">
        <title lang="en">Everyday Italian</title>
        <author>Giada De Laurentiis</author>
        <year>2005</year>
        <price>30.00</price>
    </book>
    <book category="children">
        <title lang="en">Harry Potter</title>
        <author>J K. Rowling</author>
        <year>2005</year>
        <price>29.99</price>
        <ISBN>
            <Random>12354</Random>
        </ISBN>
    </book>
    <book category="web">
        <title lang="en">XQuery Kick Start</title>
        <author>James McGovern</author>
        <author>Per Bothner</author>
        <author>Kurt Cagle</author>
        <author>James Linn</author>
        <author>Vaidyanathan Nagarajan</author>
        <year>2003</year>
        <price>49.99</price>
    </book>
    <book category="web">
        <title lang="en">Learning XML</title>
        <author>Erik T. Ray</author>
        <year>2003</year>
        <ISBN>
            <Random>12345</Random>
        </ISBN>
        <price>39.95</price>
    </book>
</bookstore>

按 XPath 过滤

/书店/书/书名 /书店/书/年 /bookstore/book/ISBN/随机
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
    <book category="cooking">
        <title lang="en">Everyday Italian</title>       
        <year>2005</year>
    </book>
    <book category="children">
        <title lang="en">Harry Potter</title>
        <year>2005</year>
        <ISBN>
            <Random>12354</Random>
        </ISBN>
    </book>
    <book category="web">
        <title lang="en">XQuery Kick Start</title>
        <year>2003</year>
    </book>
    <book category="web">
        <title lang="en">Learning XML</title>
        <year>2003</year>
        <ISBN>
            <Random>12345</Random>
        </ISBN>
    </book>
</bookstore> 

【问题讨论】:

【参考方案1】:

看起来像 XQuery 作业,例如你可以像这样重新创建你的文档

<bookstore>
  for $book in /bookstore/*
  return <book category="$book/@category">
    $book/title
    $book/year
    $book/ISBN
  </book>
</bookstore>

使用本书的例子来得到它下面的结果。您可以在此处使用 XQuery 作为选项在线测试此功能https://www.videlibri.de/cgi-bin/xidelcgi

可能有一些方法可以运行XQuery from R,但我宁愿在命令行的预处理步骤中使用xidel 之类的工具来运行。

【讨论】:

预处理应用程序不适用于我 - R、Python、SQL【参考方案2】:

所有元素都可以在一个适用于多种语言的 XPath 1.0 表达式中查找:

/bookstore/book/descendant::*[name()="title" or name()="year" or name()="Random"]

等价/相似表达:

/bookstore/book/title | /bookstore/book/year | /bookstore/book/ISBN/Random
 //book/@category | //book/year | //ISBN/Random

过滤掉元素:

//book/*[not(name()="title" or name()="year" or name()="ISBN" or name()="Random")]

对于带有命名空间的 XML,如果不使用命名空间处理,则可以使用 local-name() 代替 name()

对于给定的示例和元素以及命令行上的测试:

echo 'cat /bookstore/book/descendant::*[name()="title" or name()="year" or name()="Random"]' | xmllint --shell test.xml

结果:

/ > cat /bookstore/book/descendant::*[name()="title" or name()="year" or name()="Random"]
 -------
<title lang="en">Everyday Italian</title>
 -------
<year>2005</year>
 -------
<title lang="en">Harry Potter</title>
 -------
<year>2005</year>
 -------
<Random>12354</Random>
 -------
<title lang="en">XQuery Kick Start</title>
 -------
<year>2003</year>
 -------
<title lang="en">Learning XML</title>
 -------
<year>2003</year>
 -------
<Random>12345</Random>
/ >

对于提到的 R 崩溃,值得一看 here。

【讨论】:

这可能适用于像示例这样不太复杂的文件,但我处理的文件看起来像 github.com/HL7/C-CDA-Examples/blob/master/General/… 嗯,xpath 应该有助于在几乎任何文件上查找节点。请在该文件上发布您想要/不想要的元素,我可以稍后查看。 我想在justpaste.it/84boj删除值和属性的xpath列表 您要删除元素或属性还是仅删除它们的值?有点对文档进行匿名化?此外,上面列表中的 xpaths 不包含任何 @ 属性,如 //book/@category @Bristle 刚刚添加了一个链接,指向我关于 R 崩溃的答案。

以上是关于通过 Xpaths 从 R 中的文件中删除或过滤 XML 节点的主要内容,如果未能解决你的问题,请参考以下文章

从 R 中的字符向量中删除引号

从 R 中的列表中过滤值

如何通过基于R中的条件过滤行来读取文件

从SPSS导入时如何从R中的数据框中删除空格

如何使用rpart或party包过滤R中决策树中的自变量

如何从 R 中的 ngram 标记列表中有效地删除停用词