2012-04-20 67 views
3

考虑下面的代码:为什么Nokogiri的to_xhtml从`name`创建新的`id`属性?

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属性具有相同的值。
  3. 有没有什么办法可以避免这种情况,因为希望在可能有<a name="foo">的输入上使用to_xhtml方法?

这个问题是因为我有一些输入我有id属性的一个元素和一个单独的元素与name属性恰好冲突解析。

+0

天哪我只是浪费了我一生的2个小时,直到我意识到它正在这样做... – Blacksad 2013-01-02 09:13:50

回答

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

为什么它的价值,它看起来像这是罪魁祸首:http://git.gnome.org/browse/libxml2/树/ xmlsave.c?ID = v2.7.8#n1291。上面这段代码的注释是“C.8”,我猜是指[XHTML规范的C.8节](http://www.w3.org/TR/xhtml1/#C_8)谈论'id's和'name's。 – matt 2012-04-20 20:31:29

+0

@matt谢谢;这是我在我的问题中链接到的同一部分。也许我的阅读理解能力并不适合鼻烟,但我不确定C.8如何直接暗示这一要求(而4.10,从我上面的回答中可以明显看出)。但是,您发现源代码行和注释非常棒。 – Phrogz 2012-04-20 20:40:46

+0

嗯_my_阅读理解能力当然需要工作,因为我没有注意到你的问题中的链接。我同意C节8似乎并不需要这个,而4.10确实如此。 – matt 2012-04-20 20:49:04

1

也许你可以一些其他id值添加到这些因素,以防止libxml的加入了自己。

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

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

相关问题