当我使用 XML 包在 R 中解析此 XML 时,为什么“//*”是唯一有效的 xPath 查询?

Why is "//*" the only xPath query that works when I'm parsing this XML in R using the XML-package?

我正在使用 R 和 XML 包解析瑞典图书馆目录。使用库的 API,我从包含我的查询的 url 中得到 XML。

我想使用 xPath 查询来解析每条记录,但是我使用 XML-包 returns 空白列表的 xPath 所做的一切,除了“//*”之外的所有内容。我不是 xml-parsing 和 xPath 方面的专家,但我怀疑它与我的 API returns 对我的 xml 有关。

这是目录中单曲 post 的简单示例:

library(XML)

example.url <- "http://libris.kb.se/sru/swepub?version=1.1&operation=searchRetrieve&query=mat:dok&maximumRecords=1&recordSchema=mods"
doc = xmlParse(example.url)

# Title
works <- xmlRoot(doc)[[4]][["record"]][["recordData"]][["mods"]][["titleInfo"]][["title"]][[1]]
doesntwork <- getNodeSet(doc, "//title")

# The only xPath that returns anything
onlythisworks <- getNodeSet(doc, "//*")

如果这与命名空间有关(as these answers sugests),我所理解的是 API returns 数据似乎在初始标记中定义了命名空间,我可以使用它,但这对我没有帮助:

# Namespaces are confusing:
title <- getNodeSet(xmlRoot(doc), "//xsi:title", namespaces = c(xsi = "http://www.w3.org/2001/XMLSchema-instance"))

这是(再次)the example return data 我正在尝试解析的内容。

您必须使用正确的命名空间。 尝试以下

doesntwork <- getNodeSet(doc, "//mods:title")
#[[1]]
#<title>Horizontal Slot Waveguides for Silicon Photonics Back-End Integration [Elektronisk resurs]</title> 
#
#[[2]]
#<title>TRITA-ICT/MAP AVH, 2014:17                      \
#                           </title> 
#
#attr(,"class")
#[1] "XMLNodeSet"

顺便说一句:我通常通过

获取命名空间
nsDefs=xmlNamespaceDefinitions(doc,simplify = TRUE,recursive=TRUE)

但这会在您的案例中引发错误。它抱怨有 different URIs for the same name space prefix。根据 this site 这似乎不是好的编码风格。


根据 OP 的评论更新

我自己不是 xml 专家,但这是我的看法:您可以通过 <tag xmlns=URI> 定义默认命名空间。非默认命名空间的形式为 <tag xmlns:a=URI>,其中 a 是各自的命名空间名称。 您的文档的问题是有两个不同的默认命名空间。第一个在 <searchRetrieveResponse xmlns="http://www.loc.gov/zing/srw/" ... >。第二个在 <mods xmlns="http://www.loc.gov/mods/v3" ... >。此外,您会发现第一个标记中的第二个默认命名空间 URI 为 xmlns:mods="http://www.loc.gov/mods/v3"(此处为 non-default)。这看起来相当混乱。现在,<title> 标签位于 <mods> 标签内。我认为 <mods> 中定义的默认命名空间被 searchRetrieveResponse 的非默认命名空间覆盖(因为它们具有相同的 URI)。因此,尽管 <mods> 和所有后续标记(如 <title>)似乎具有默认名称空间,但它们实际上具有 xmlns:mods 名称空间。但这不适用于标签 <numberOfRecords>(因为它在 <mods> 之外)。您可以通过

访问此节点
getNodeSet(doc, "//ns:numberOfRecords",
       namespaces = c(ns="http://www.loc.gov/zing/srw/"))

在这里,您提取在 <searchRetrieveResponse> 中定义的默认名称空间并为其命名(在我们的例子中为 ns)。然后您可以在 xPath 查询中显式使用默认命名空间名称。