Разбор XML с использованием R, имеющего пространства имен
Ниже приведен ответ в формате xml, который я получил от sharepoint. Я пытаюсь проанализировать данные и получить подробности в следующем формате.
Требуется выход
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
не может быть обнаружен
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
Предполагая, что текст находится в 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))
Рассмотреть вопрос о регистрации 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