在R中调用getSibling()从XML文件中提取单个节点会导致崩溃

问题描述:

我试图从使用R脚本的非常大的(〜620 MB)XML文件中一次提取一个节点。我想要访问的每个主节点对应于不同的药物,并且所有节点都相互平行。我的目标是一次处理整个文件,一个节点,因为试图将整个文件读入内存不能与R中的XML解析器一起工作。在R中调用getSibling()从XML文件中提取单个节点会导致崩溃

我已经将大型XML文件显着截断为更小仅包含4个节点的示例文件;该XML文件的开头是这样的:

<?xml version="1.0" encoding="UTF-8"?> 
<drugbank xmlns="http://www.drugbank.ca" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.drugbank.ca http://www.drugbank.ca/docs/drugbank.xsd" version="5.0" exported-on="2017-07-06"> 
<drug type="biotech" created="2005-06-13" updated="2016-08-17"> 
    <drugbank-id primary="true">DB00001</drugbank-id> 
    <drugbank-id>BTD00024</drugbank-id> 
    <drugbank-id>BIOD00024</drugbank-id> 
    <name>Lepirudin</name> 
    <description>Lepirudin is identical to natural hirudin except for substitution of leucine for isoleucine at the N-terminal end of the molecule and the absence of a sulfate group on the tyrosine at position 63. It is produced via yeast cells. Bayer ceased the production of lepirudin (Refludan) effective May 31, 2012.</description> 
    <cas-number>138068-37-8</cas-number> 
    <unii>Y43GF64R34</unii> 
    <state>liquid</state> 
    <groups> 
    <group>approved</group> 
    </groups> 

在审查可用的选项,并且想使用我已经写了提取期望从XML文件中的字段(它适用于小型的XML文件将R脚本,但大文件失败),似乎在R中的XML库中使用getSibling()函数是我的最佳选择。下面的示例代码(来自http://svitsrv25.epfl.ch/R-doc/library/XML/html/addSibling.html)的作品中提取单个节点在此示例文件:

f = system.file("exampleData", "job.xml", package = "XML") 
tt = as(xmlParse(f), "XMLHashTree") 
x = xmlRoot(tt, skip = FALSE) 
DesiredOutput <- getSibling(x) 
# I’m still not sure how to “walk” to the next sibling after the above process completes, since this example file only contains one node, and there is no simple way to increment a counter using the above code 

这个例子job.xml文件的开头如下:

<!-- Initial Comment --> 
<gjob:Helping xmlns:gjob="http://www.gnome.org/some-location"> 
    <gjob:Jobs> 

    <gjob:Job> 
     <gjob:Project ID="3"/> 
     <gjob:Application>GBackup</gjob:Application> 
     <gjob:Category>Development</gjob:Category> 

     <gjob:Update> 
     <gjob:Status>Open</gjob:Status> 
     <gjob:Modified>Mon, 07 Jun 1999 20:27:45 -0400 MET DST</gjob:Modified> 
     <gjob:Salary>USD 0.00</gjob:Salary> 
     </gjob:Update> 

     <gjob:Developers> 
     <gjob:Developer> 
     </gjob:Developer> 
     </gjob:Developers> 

但是,如果我代替我自己XML文件(完整文件的小版本;我已签,这是合法的XML格式,因为我的[R脚本运行正确处理它),下面的代码崩溃R:

f = "MyTruncatedExampleFile.xml" -> this line causes R to crash 
tt = as(xmlParse(f), "XMLHashTree") 
x = xmlRoot(tt, skip = FALSE) 
DesiredOutput <- getSibling(x) 

任何人都可以提出为什么我自己的小XML文件会导致崩溃,但示例job.xml文件运行正确吗?提前感谢您的见解。

+0

它可能是r的错误吗? –

显然,它似乎是由于截断的XML中未声明的命名空间前缀导致崩溃:xmlns="http://www.drugbank.ca"。如果删除它,该方法不会使R崩溃。请注意:未声明的名称空间在XML文档中有效。所以,这个问题应该由XML包作者提出。另外,由于<drug>在截断XML中没有兄弟,所以xmlChildren()用于代替getSibling()

# CRASHES 
f = "DrugBank.xml" 
tt = as(xmlParse(f), "XMLHashTree") 
x = xmlRoot(tt, skip = FALSE) 
DesiredOutput <- xmlChildren(x)[[1]] 
DesiredOutput 

# NO CRASHES 
f = "DrugBank_oth.xml"      # REMOVED UNDEFINED NAMESPACE PREFIX 
tt = as(xmlParse(f), "XMLHashTree") 
x = xmlRoot(tt, skip = FALSE) 
DesiredOutput <- xmlChildren(x)[[1]] 
DesiredOutput 

由于没有修改原始的XML解决办法,考虑getNodeSet在此定义为特殊的命名空间和XPath到根的王氏/*/*孩子水平的前缀。索引[[1]]用于取代第一个节点而不是所有节点。在这里,网络被用作前缀,但它可以是任何东西。

# NO CRASHES 
f = "DrugBank.xml" 
doc = xmlParse(f) 
nmsp = c(web="http://www.drugbank.ca")  # DEFINE NAMESPACE PREFIX 

DesiredOutput <- getNodeSet(doc, "/*/*", nmsp)[[1]] 
DesiredOutput 

# <drug type="biotech" created="2005-06-13" updated="2016-08-17"> 
# <drugbank-id primary="true">DB00001</drugbank-id> 
# <drugbank-id>BTD00024</drugbank-id> 
# <drugbank-id>BIOD00024</drugbank-id> 
# <name>Lepirudin</name> 
# <description>Lepirudin is identical to natural hirudin except for 
#    substitution of leucine for isoleucine at the N-terminal 
#    end of the molecule and the absence of a sulfate group on 
#    the tyrosine at position 63. It is produced via yeast 
#    cells. Bayer ceased the production of lepirudin (Refludan) 
#    effective May 31, 2012.</description> 
# <cas-number>138068-37-8</cas-number> 
# <unii>Y43GF64R34</unii> 
# <state>liquid</state> 
# <groups> 
#  <group>approved</group> 
# </groups> 
# </drug>