【问题标题】:Parse XML using R having namespaces使用具有命名空间的 R 解析 XML
【发布时间】:2017-04-21 23:53:26
【问题描述】:

以下是我从共享点获得的 xml 响应 我正在尝试解析数据并获取以下格式的详细信息

需要输出

title port space    datecreat               id
test  8080 100.000 2017-04-21 17:29:23      1
apple  8700 108.000 2017-04-21 18:29:23     2

收到输入

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <soap:Body>
        <GetListItemsResponse xmlns="http://schemas.microsoft.com/sharepoint/soap/">
            <GetListItemsResult>
                <listitems xmlns:s='uuid:SBDSHDSH-DSJHD' xmlns:dt='uuid:CSDSJHA-DGGD' xmlns:rs='urn:schemas-microsoft-com:rowset' xmlns:z='#RowsetSchema'
                    <rs:data ItemCount="2">
                        <z:row title="test" port="8080" space='100.000' datecreat='2017-04-21 17:29:23' id='1' />
                        <z:row title="apple" port="8700" space='108.000' datecreat='2017-04-21 17:29:23' id='2' />
                    </rs:data>
                </listitems>
            </GetListItemsResult>
        </GetListItemsResponse>
    </soap:Body>
</soap:Envelope>

我是 R 新手,尝试了一些,但没有一个有效。命名空间和 z:row 无法被检测到。

【问题讨论】:

  • 这不太可能是您从 SharePoint 获得的确切响应,因为它是格式错误的 XML。

标签: r xml xpath xml-parsing parsexml


【解决方案1】:

考虑注册 z 命名空间前缀并使用 XML 的内部变量 xmlAttrsToDataframe 使用三冒号运算符:

library(XML)

txt='<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 <soap:Body>
  <GetListItemsResponse xmlns="http://schemas.microsoft.com/sharepoint/soap/">
    <GetListItemsResult>
      <listitems xmlns:s=\'uuid:SBDSHDSH-DSJHD\' xmlns:dt=\'uuid:CSDSJHA-DGGD\' xmlns:rs=\'urn:schemas-microsoft-com:rowset\' xmlns:z=\'#RowsetSchema\'>
        <rs:data ItemCount="2">
          <z:row title="test" port="8080" space=\'100.000\' datecreat=\'2017-04-21 17:29:23\' id=\'1\' />
          <z:row title="apple" port="8700" space=\'108.000\' datecreat=\'2017-04-21 17:29:23\' id=\'2\' />
        </rs:data>
      </listitems>
    </GetListItemsResult>
  </GetListItemsResponse>
 </soap:Body>
</soap:Envelope>'

doc <- xmlParse(txt)

namespaces <- c(z="#RowsetSchema")
df <- XML:::xmlAttrsToDataFrame(getNodeSet(doc, path='//z:row', namespaces))

df
#   title port   space           datecreat id
# 1  test 8080 100.000 2017-04-21 17:29:23  1
# 2 apple 8700 108.000 2017-04-21 17:29:23  2

【讨论】:

    【解决方案2】:

    假设文本在Lines 中,一种方法是将grep 移出z:row 行,用空格替换等号并使用read.table 读取。第一行读取包含一些垃圾列的行,第二行删除垃圾列并设置列名。请注意,即使 XML 无效,这也会起作用。不使用任何包。

    DF <- read.table(text = gsub("=", " ", grep("z:row", Lines, value = TRUE)))
    setNames(DF[seq(3, ncol(DF), 2)], unlist(DF[1, seq(2, ncol(DF)-2, 2)]))
    

    给予:

      title port space           datecreat id
    1  test 8080   100 2017-04-21 17:29:23  1
    2 apple 8700   108 2017-04-21 17:29:23  2
    

    注意:假设输入为:

    Lines <- c(" <?xml version=\"1.0\" encoding=\"utf-8\"?>", "        <soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">", 
    "            <soap:Body>", "                <GetListItemsResponse xmlns=\"http://schemas.microsoft.com/sharepoint/soap/\">", 
    "                    <GetListItemsResult>", "                            <listitems xmlns:s='uuid:SBDSHDSH-DSJHD' xmlns:dt='uuid:CSDSJHA-DGGD' xmlns:rs='urn:schemas-microsoft-com:rowset' xmlns:z='#RowsetSchema'", 
    "                                <rs:data ItemCount=\"2\">", 
    "                                    <z:row title=\"test\" port=\"8080\" space='100.000' datecreat='2017-04-21 17:29:23' id='1' />", 
    "                                    <z:row title=\"apple\" port=\"8700\" space='108.000' datecreat='2017-04-21 17:29:23' id='2' />", 
    "                            </rs:data>", "                        </listitems>", 
    "                    </GetListItemsResult>", "                </GetListItemsResponse>", 
    "            </soap:Body>", "        </soap:Envelope>")
    

    如果您的输入是一个以换行符分隔的长字符串 Lines_n,那么首先运行它:

    Lines <- readLines(textConnection(Lines_n))
    

    【讨论】:

      【解决方案3】:

      这不是有效的 XML,虽然我是第一个抱怨 SharePoint 的人,但它本身不会产生损坏的东西。一个正在攻击您的 SharePoint 服务器的同事完全有可能破坏了某些东西,但要破坏它真的很难。

      无论如何,这是 XML 的有效版本:

      <?xml version="1.0" encoding="utf-8"?>
      <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
          <soap:Body>
              <GetListItemsResponse xmlns="http://schemas.microsoft.com/sharepoint/soap/">
                  <GetListItemsResult>
                      <listitems xmlns:s='uuid:SBDSHDSH-DSJHD' xmlns:dt='uuid:CSDSJHA-DGGD' xmlns:rs='urn:schemas-microsoft-com:rowset' xmlns:z='#RowsetSchema'>
                          <rs:data ItemCount="2">
                              <z:row title="test" port="8080" space='100.000' datecreat='2017-04-21 17:29:23' id='1' />
                              <z:row title="apple" port="8700" space='108.000' datecreat='2017-04-21 17:29:23' id='2' />
                          </rs:data>
                      </listitems>
                  </GetListItemsResult>
              </GetListItemsResponse>
          </soap:Body>
      </soap:Envelope>
      

      而且,它可以很好地解析和提取:

      library(xml2)
      
      doc <- read_xml("test.xml")
      
      ns <- xml_ns_rename(xml_ns(doc), d1 = "a")
      
      xml_find_all(doc, ".//z:row") %>% 
        map(xml_attrs) %>% 
        map_df(as.list) 
      
      ## # A tibble: 2 × 5
      ##   title  port   space           datecreat    id
      ##   <chr> <chr>   <chr>               <chr> <chr>
      ## 1  test  8080 100.000 2017-04-21 17:29:23     1
      ## 2 apple  8700 108.000 2017-04-21 17:29:23     2
      

      【讨论】:

      • xml2 库在我们的服务器中仍然不可用,并且需要时间来安装它。但它绝对适用于本地系统。感谢您的回复
      • 为什么需要将d1命名空间重命名为a
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-03
      • 2014-01-10
      • 2014-06-14
      • 1970-01-01
      • 2010-11-08
      相关资源
      最近更新 更多