我试图通过使用Nokogiri扫描节点的内容,然后执行gsub
来替换一组文件中唯一字符串的示例。我保留了部分字符串,并将其转换为锚标记。然而,大多数节点的内容中有各种形式的标记,而不仅仅是简单的字符串。例如,假设我有一个这样的文件:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<html>
<head>
<title>Title</title>
<link href="style.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div>
<p class="header"><<2>>Header</p>
<p class="paragraph">
<p class="text_style">Lorem ipsum blah blah blah. <<3>> Here is more content. <span class="style">Preserve this.</span> Blah blah extra text.</p>
</div>
</body>
</html>
字符串
整个文档中都有数字,被<<
和>>
包围。我想把数字的值转换成这样的标记:<a id='[#]'/>
,但我想保留同一节中其他元素的HTML标记,即<span class="style">Preserve this.</span>
。
以下是我尝试过的所有方法:
file = File.open("file.xhtml") {|f| Nokogiri::XML(f)}
file.xpath("//text()").each { |node|
if node.text.match(/<<([^_]*)>>/)
new_content = node.text.gsub(/<<([^_]*)>>/,"<a id=\"\\1\"/>")
node.parent.inner_html = new_content
end
}
型gsub
可以正常工作,但是因为它使用了.text
方法,所以任何标记都被忽略并有效地清除。在这种情况下,<span class="style">Preserve this.</span>
部分被完全删除。(仅供参考,我使用.parent
方法,因为如果我只执行node.inner_html = new_content
,我会得到这个错误:add_child_node': cannot reparent Nokogiri::XML::Element there (ArgumentError)
。)
如果我这样做:
new_content = node.text.gsub(/<<([^_]*)>>/,"<a id=\"\\1\"/>")
node.content = new_content
型
字符没有被正确转义:文件以<a id="3"/>
而不是<a id="3"/>
结束。
我尝试使用CSS方法,而不是像这样:
file.xpath("*").each { |node|
if node.inner_html.match(/<<([^_]*)>>/)
new_content = node.inner_html.gsub(/<<([^_]*)>>/,"<a id=\"\\1\"/>")
node.inner_html = new_content
end
}
型gsub
工作,标记被保留,被替换的标记被正确转义。但是<head>
和<body>
标记被删除,这导致无效文件:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>Title</title>
<link href="style.css" rel="stylesheet" type="text/css"/>
<div>
<p class="header"><a id="2"/>Header</p>
<p class="paragraph">
</p><p class="text_style">Lorem ipsum blah blah blah. <a id="3"/> Here is more content. <span class="style">Preserve this.</span> Blah blah extra text. </p>
</div>
</html>
型
我怀疑这与我迭代所有节点(file.css("*")
)有关,这也是冗余的,因为除了子节点之外,还扫描了父节点。
我已经搜索了网络,但找不到任何解决方案。我只是想能够交换出唯一的文本,同时保持标记,并使其正确编码。有什么非常明显的,我错过了这里?
2条答案
按热度按时间kse8i1jr1#
这看起来工作得很好:
字符串
其结果是:
型
Nokogiri正在添加
型
行,可能是因为标记被定义为XML。
选择器
"//text()[contains(.,'<<')]"
只查找包含'<<'
的文本节点。如果可能导致误报,您可能需要修改它以使其更具体。有关语法,请参阅“XPath: using regex in contains function“。replace
正在执行技巧;您试图修改Nokogiri::XML::Text节点以包含<a.../>
,但它不能,<
和>
必须被编码。将节点更改为Nokogiri::XML::Element,这是Nokogiri默认的<a id="[2]">
,让它按照您的需要存储它。guicsvcw2#
在我的例子中,我有一个
Nokogiri::XML::Element
,我通过记录类发现:puts content.class
个为了在不改变HTML/XML结构的情况下更改文本,必须使用递归函数向下钻取到文档的叶子。
字符串
使用方法:
型