6

我有一个输入 xml 文件。

猫样本.xml

<Text>
    &lt;p&gt;ABC &lt;/p&gt;
</Text>

R 脚本

library(XML)
doc = xmlTreeParse("sample.xml", useInternal = TRUE)
top<-xmlRoot(doc)

sub("&lt;","<",top[[1]])

我该如何解决 pblm 以上问题?

错误消息:as.vector(x, "character") 中的错误:无法将类型“externalptr”强制转换为“字符”类型的向量

编辑:目的是对 xml 中的特定节点使用 readHTMLTable() 函数,该节点具有 html 表,但它具有用于 > 和 < 的 xml 标记(&gt;&lt;),因为 readHTMLTable 函数无法处理 xml 标记,因此需要首先重新替换。

4

3 回答 3

7

And now the answer to your real question:

sample.xml with encoded table:

<Text>
&lt;table&gt;
&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;8&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;32&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
</Text>

Read it in:

> library(XML)
> doc = xmlTreeParse("sample.xml", useInternal = TRUE)
> top<-xmlRoot(doc)

Convert to text:

> table=xmlValue(top)
> table
[1] "\n<table>\n<tr><td>1</td><td>2</td></tr>\n<tr><td>2</td><td>8</td></tr>\n<tr><td>4</td><td>32</td></tr>\n</table>\n"

This is now ready to feed to readHTMLTable. No string conversion needed:

> readHTMLTable(table)
$`NULL`
  V1 V2
1  1  2
2  2  8
3  4 32

Howzat?

于 2013-01-31T09:01:23.770 回答
6

如果您的问题是要知道如何替换 XML 节点内容中的字符串,那么您可以使用sample.xml您提供的文件检查以下代码:

## Parse the XML file
doc <- xmlTreeParse("sample.xml", useInternal = TRUE)
## Select the nodes we want to update
nodes <- getNodeSet(doc, "//Text")
## For each node, apply gsub on the content of the node
lapply(nodes, function(n) {
  xmlValue(n) <- gsub("ABC","foobar",xmlValue(n))
})

这会给你:

R> doc
<?xml version="1.0"?>
<Text>
    &lt;p&gt;foobar &lt;/p&gt;
</Text>

在这里,您可以看到“ABC”已被“foobar”取代。

但是,如果你用你想要实现的替换来尝试这个代码(用“<”替换“<”),它显然不会工作:

doc <- xmlTreeParse("sample.xml", useInternal = TRUE)
nodes <- getNodeSet(doc, "//Text")
lapply(nodes, function(n) {
  xmlValue(n) <- gsub("&lt;","<",xmlValue(n))
})

会给你 :

R> doc
<?xml version="1.0"?>
<Text>
    &lt;p&gt;ABC &lt;/p&gt;
</Text>

为什么 ?如果您正在使用 XML 文件,您应该知道某些字符,主要是 <、>、& 和 " 是保留的,因为它们是基本 XML 语法的一部分。因此,它们不能出现在节点的内容中,否则会解析会失败。所以它们被替换为实体,这是这些字符的一种编码。例如,“<”被编码为“<”,“&”被编码为“&”等。

所以这里,你节点的内容中包含了一个“<”字符,这个字符已经自动转换为他的实体“<”了。您尝试对代码执行的操作是替换“<” 返回“<”,R 很乐意为您做这件事,但由于它是节点的文本内容,XML 包会立即将其转换回“<”。

所以,如果你想要实现的是转换你的字符串 "<p>ABC </p>" 到一个新的 XML 节点“<p>ABC </p>”,你不能那样做。一种解决方案是解析您的文本字符串,从中检测节点的名称和(此处为“p”),创建一个新节点xmlNode(),为其提供文本内容“ABC”并用您刚刚的节点替换字符串创建的。

另一种快速而肮脏的方法是首先替换文件中的所有实体而不解析 XML。像这样的东西:

txt <- readLines(file("sample.xml"))
txt <- gsub("&lt;", "<", txt)
txt <- gsub("&gt;", ">", txt)
writeLines(txt, file("sample2.xml"))
doc2 <- xmlTreeParse("sample2.xml", useInternal = TRUE)

这使 :

R> doc2
<?xml version="1.0"?>
<Text>
  <p>ABC </p>
</Text>

但这很危险,因为如果有一个“真实的”“<” 文件中的实体,解析将失败。

于 2013-01-31T08:36:48.770 回答
3

获取节点的值xmlValue并替换。在这里,我将用 DEF 替换 ABC:

> top<-xmlRoot(doc)
> top
<Text>
    &lt;p&gt;ABC &lt;/p&gt;
</Text> 
> xmlValue(top)=sub("ABC","DEF",xmlValue(top))
> top
<Text>
    &lt;p&gt;DEF &lt;/p&gt;
</Text> 

我不尝试替换 < 的原因是因为这些字符序列在某些时候被 XML 代码解释:

> substr(xmlValue(top),6,6)=="<"
[1] TRUE

虽然我已经尝试过使用一些选项xmlTreeParse和其他 XML 包函数,但我似乎无法停止xmlValue解释它们......

于 2013-01-31T08:27:30.733 回答