Разбор XML в R: неправильные пространства имен

У меня есть куча файлов XML и сценарий R, который считывает их содержимое во фрейм данных. Однако теперь у меня есть файлы, которые я хотел проанализировать как обычно, но в определении их пространства имен есть что-то, что не позволяет мне нормально выбирать их значения с помощью выражений XPath.

XML-файлы выглядят так:

xml_nons.xml

<?xml version="1.0" encoding="UTF-8"?>
<XML>
   <Node>
      <Name>Name 1</Name>
      <Title>Title 1</Title>
      <Date>2015</Date>
   </Node>
</XML>

И другие:

xml_ns.xml

<?xml version="1.0" encoding="UTF-8"?>
<XML xmlns="http://www.nonexistingsite.com">
   <Node>
      <Name>Name 2</Name>
      <Title>Title 2</Title>
      <Date>2014</Date>
   </Node>
</XML>

URL-адрес, на который указывает xmlns, не существует.

Код R, который я использую, выглядит следующим образом:

library(XML)

xmlfiles <- list.files(path = ".", 
                       pattern="*.xml$", 
                       full.names = TRUE, 
                       recursive = TRUE)

n <- length(xmlfiles)
dat <- vector("list", n)

for(i in 1:n){
       doc <- xmlTreeParse(xmlfiles[i], useInternalNodes = TRUE)
       nodes <- getNodeSet(doc, "//XML")
       x <- lapply(nodes, function(x){ data.frame(
              Filename = xmlfiles[i],
              Name = xpathSApply(x, ".//Node/Name" , xmlValue),
              Title = xpathSApply(x, ".//Node/Title" , xmlValue),
              Date = xpathSApply(x, ".//Node/Date" , xmlValue)
            )})
            dat[[i]] <- do.call("rbind", x)
    }

    xml <- do.call("rbind", dat)
    xml

Однако что я получаю в результате:

Filename            Name    Title    Date
./xml_nons.xml      Name 1  Title 1  2015

Если я удалю ссылку на пространство имен из второго файла, я получу правильное:

Filename            Name    Title    Date
./xml_nons_1.xml    Name 1  Title 1  2015
./xml_ns_1.xml      Name 2  Title 2  2014

Конечно, я мог бы иметь XSL для удаления этих пространств имен из исходных XML-файлов, но я хотел бы иметь какое-то решение, которое работает в R. Есть ли способ сказать R просто игнорировать все в объявлении XML?


person nikopartanen    schedule 20.03.2015    source источник


Ответы (1)


Я думаю, что нет простого способа игнорировать пространства имен. Лучший способ — научиться жить с ними. В этом ответе будет использоваться более новый пакет XML2. Но то же самое относится и к пакетному решению XML.

Использовать

library(XML2)
fname='myfile.xml'
doc <- read_xml(fname)
#peak at the namespaces
xml_ns(doc)

Первое пространство имен назначается d1. Если XPath не находит то, что вам нужно, наиболее вероятной причиной является проблема с пространством имен.

xpath <-  "//d1:FormDef"
ns <- xml_find_all(doc,xpath, xml_ns(doc))
ns

Кроме того, вы должны сделать это для каждого элемента пути. Поэтому, чтобы не печатать, вы можете сделать

library(stringr)
> xpath <-  "/ODM/Study"
> (xpath<-str_replace_all(xpath,'/','/d1:'))
[1] "/d1:ODM/d1:Study"
person userJT    schedule 28.07.2015