【问题标题】:Parse Nested XML (with namespaces) in R在 R 中解析嵌套 XML(带有命名空间)
【发布时间】:2017-08-11 11:30:59
【问题描述】:

我正在尝试解析来自 Web API 的 xml 响应。

对于如下简单的 xml,我可以使用 xpathSApply 并非常轻松地获取相关数据。

下面是example.xml

<?xml version="1.0" encoding="UTF-8"?>
<CATALOG>
    <PLANT>
        <COMMON>Bloodroot</COMMON>
        <BOTANICAL>Sanguinaria canadensis</BOTANICAL>
        <ZONE>4</ZONE>
        <LIGHT>Mostly Shady</LIGHT>
        <PRICE>$2.44</PRICE>
        <AVAILABILITY>031599</AVAILABILITY>
    </PLANT>
    <PLANT>
        <COMMON>Columbine</COMMON>
        <BOTANICAL>Aquilegia canadensis</BOTANICAL>
        <ZONE>3</ZONE>
        <LIGHT>Mostly Shady</LIGHT>
        <PRICE>$9.37</PRICE>
        <AVAILABILITY>030699</AVAILABILITY>
    </PLANT>
</CATALOG>

>library(XML)
>doc<-xmlTreeParse("example.xml",useInternal=TRUE) 
>rootNode<-xmlRoot(doc)
>xpathSApply(rootNode,"//COMMON",xmlValue)
[1] "Bloodroot" "Columbine"

> getNodeSet(doc,"//PLANT")
[[1]]
<PLANT>
  <COMMON>Bloodroot</COMMON>
  <BOTANICAL>Sanguinaria canadensis</BOTANICAL>
  <ZONE>4</ZONE>
  <LIGHT>Mostly Shady</LIGHT>
  <PRICE>$2.44</PRICE>
  <AVAILABILITY>031599</AVAILABILITY>
</PLANT> 

[[2]]
<PLANT>
  <COMMON>Columbine</COMMON>
  <BOTANICAL>Aquilegia canadensis</BOTANICAL>
  <ZONE>3</ZONE>
  <LIGHT>Mostly Shady</LIGHT>
  <PRICE>$9.37</PRICE>
  <AVAILABILITY>030699</AVAILABILITY>
</PLANT> 

attr(,"class")
[1] "XMLNodeSet"

> xmlSApply(getNodeSet(rootNode,"//PRICE"),xmlValue) #provides a list of all PRICE values in the xml
[1] "$2.44" "$9.37"

但是,相同的命令不适用于以下具有命名空间详细信息的 xml。无论如何我可以获取节点/标签中的数据。

下面是example1.xml

<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><s:Body><GetByFilterTradeResponse xmlns="http://entrader.contigoenergy.com/Contigo.Entrader.Service"><GetByFilterTradeResult xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<CATALOG>
    <CATEGORY>
        <FAMILY>
            <PLANT>
                <COMMON>Bloodroot</COMMON>
                <BOTANICAL>Sanguinaria canadensis</BOTANICAL>
                <ZONE>4</ZONE>
                <DETAILS>
                    <PRICEINBULK>2.3</PRICEINBULK>
                    <MINVOLUME>100</MINVOLUME>
                </DETAILS>
                <LIGHT>Mostly Shady</LIGHT>
                <PRICE>$2.44</PRICE>
                <AVAILABILITY>031599</AVAILABILITY>
            </PLANT>
            <PLANT>
                <COMMON>Columbine</COMMON>
                <BOTANICAL>Aquilegia canadensis</BOTANICAL>
                <ZONE>3</ZONE>
                <DETAILS>
                    <PRICEINBULK>9.00</PRICEINBULK>
                    <MINVOLUME>100</MINVOLUME>
                </DETAILS>
                <LIGHT>Mostly Shady</LIGHT>
                <PRICE>$9.37</PRICE>
                <AVAILABILITY>030699</AVAILABILITY>
            </PLANT>
        </FAMILY>
    </CATEGORY> 
</CATALOG>
</GetByFilterTradeResult></GetByFilterTradeResponse></s:Body></s:Envelope>

以下命令不会从上述 xml 中提取节点值

>doc<-xmlTreeParse("example1.xml",useInternal=TRUE) 
>rootNode<-xmlRoot(doc) 
> xpathSApply(rootNode,"//COMMON",xmlValue) 
list()

> getNodeSet(doc,"//PLANT")
list()
attr(,"class")
[1] "XMLNodeSet"

> xmlSApply(getNodeSet(rootNode,"//PRICE"),xmlValue) 
list()

【问题讨论】:

    标签: r xml xpath xml-parsing nested


    【解决方案1】:

    在您的 XPATH 中使用 name()local-name()

    library(XML)
    
    appText <- '<?xml version="1.0" encoding="UTF-8"?>
    <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
    <s:Body><GetByFilterTradeResponse xmlns="http://entrader.contigoenergy.com/Contigo.Entrader.Service">
    <GetByFilterTradeResult xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    <CATALOG>
    <CATEGORY>
    <FAMILY>
    <PLANT>
    <COMMON>Bloodroot</COMMON>
    <BOTANICAL>Sanguinaria canadensis</BOTANICAL>
    <ZONE>4</ZONE>
    <DETAILS>
    <PRICEINBULK>2.3</PRICEINBULK>
    <MINVOLUME>100</MINVOLUME>
    </DETAILS>
    <LIGHT>Mostly Shady</LIGHT>
    <PRICE>$2.44</PRICE>
    <AVAILABILITY>031599</AVAILABILITY>
    </PLANT>
    <PLANT>
    <COMMON>Columbine</COMMON>
    <BOTANICAL>Aquilegia canadensis</BOTANICAL>
    <ZONE>3</ZONE>
    <DETAILS>
    <PRICEINBULK>9.00</PRICEINBULK>
    <MINVOLUME>100</MINVOLUME>
    </DETAILS>
    <LIGHT>Mostly Shady</LIGHT>
    <PRICE>$9.37</PRICE>
    <AVAILABILITY>030699</AVAILABILITY>
    </PLANT>
    </FAMILY>
    </CATEGORY> 
    </CATALOG>
    </GetByFilterTradeResult></GetByFilterTradeResponse></s:Body></s:Envelope>'
    doc <- xmlParse(appText)
    > xpathSApply(doc,"//*[name()='COMMON']", xmlValue)
    [1] "Bloodroot" "Columbine"
    

    或者显式定义命名空间:

    > xpathSApply(doc,"//n:COMMON",xmlValue, namespaces = 
    +                 c(s = "http://schemas.xmlsoap.org/soap/envelope/", 
    +                   n = "http://entrader.contigoenergy.com/Contigo.Entrader.Service", 
    +                   i = "http://www.w3.org/2001/XMLSchema-instance")) 
    [1] "Bloodroot" "Columbine"
    

    或使用xml2 包:

    library(xml2)
    doc <- read_xml(appText)
    # check namespaces
    > xml_ns(doc)
    d1 <-> http://entrader.contigoenergy.com/Contigo.Entrader.Service
    i  <-> http://www.w3.org/2001/XMLSchema-instance
    s  <-> http://schemas.xmlsoap.org/soap/envelope/
    u  <-> http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd
    
    > xml_text(xml_find_all(doc, "//d1:COMMON"))
    [1] "Bloodroot" "Columbine"
    

    【讨论】:

    • 非常感谢@jdharrison。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-24
    • 1970-01-01
    • 2023-03-12
    • 2010-11-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多