为什么Nokogiri的to_xhtml会从`name`创建新的`id`属性?

时间:2012-04-20 19:51:51

标签: ruby xhtml nokogiri libxml2

请考虑以下代码:

require 'nokogiri' # v1.5.2
doc = Nokogiri.XML('<body><a name="foo">ick</a></body>')

puts doc.to_html
#=> <body><a name="foo">ick</a></body>

puts doc.to_xml
#=> <?xml version="1.0"?>
#=> <body>
#=>   <a name="foo">ick</a>
#=> </body>

 puts doc.to_xhtml
 #=> <body>
 #=>   <a name="foo" id="foo">ick</a>
 #=> </body>

请注意已创建的新id属性。

  1. 谁对此负责,Nokogiri或libxml2?
  2. 为什么会这样? (这是执行标准吗?)
    我能找到的最接近的是this spec,其中描述了可能如何将idname属性设置为相同的值。 < / LI>
  3. 有没有办法避免这种情况,因为希望在可能有to_xhtml的输入上使用<a name="foo">方法?
  4. 出现这个问题是因为我有一些输入,我在一个元素上使用id属性进行解析,而一个元素与name属性碰巧发生冲突。 < / p>

2 个答案:

答案 0 :(得分:2)

显然是libxml2的it's a feature。在http://www.w3.org/TR/xhtml1/#h-4.10我们找到:

  

在XML中,片段标识符的类型为ID,每个元素只能有一个类型为ID的属性。因此,在XHTML 1.0中,id属性被定义为ID类型。为了确保XHTML 1.0文档是结构良好的XML文档,XHTML 1.0文档必须在上面列出的元素上定义片段标识符时使用id属性。
  [...]
  请注意,在XHTML 1.0中,这些元素的name属性已被正式弃用,并将在后续版本的XHTML中删除。

我提出的最佳“解决方法”是:

# Destroy all <a name="..."> elements, replacing with children
# if another element with a conflicting id already exists in the document
doc.xpath('//a[@name][not(@id)][not(@href)]').each do |a|
  a.replace(a.children) if doc.at_css("##{a['name']}")
end

答案 1 :(得分:1)

也许您可以为这些元素添加一些其他id值,以防止libxml添加自己的值。

doc.xpath('//a[@name and not(@id)]').each do |n|
  n['id'] = n['name'] + 'some_suffix'
end

(显然,您需要确定如何为文档创建唯一的id值。