Có cách nào dễ dàng để chuyển đổi tài liệu XML Nokogiri thành Hash không?Chuyển đổi tài liệu Nokogiri thành Ruby Hash
Giống như Rails 'Hash.from_xml
.
Có cách nào dễ dàng để chuyển đổi tài liệu XML Nokogiri thành Hash không?Chuyển đổi tài liệu Nokogiri thành Ruby Hash
Giống như Rails 'Hash.from_xml
.
Tôi sử dụng mã này với libxml-ruby (1.1.3). Tôi đã không sử dụng nokogiri bản thân mình, nhưng tôi hiểu rằng nó sử dụng libxml-ruby anyway. Tôi cũng khuyến khích bạn xem ROXML (http://github.com/Empact/roxml/tree) để ánh xạ các phần tử xml vào các đối tượng ruby; nó được xây dựng trên đỉnh libxml.
# USAGE: Hash.from_libxml(YOUR_XML_STRING)
require 'xml/libxml'
# adapted from
# http://movesonrails.com/articles/2008/02/25/libxml-for-active-resource-2-0
class Hash
class << self
def from_libxml(xml, strict=true)
begin
XML.default_load_external_dtd = false
XML.default_pedantic_parser = strict
result = XML::Parser.string(xml).parse
return { result.root.name.to_s => xml_node_to_hash(result.root)}
rescue Exception => e
# raise your custom exception here
end
end
def xml_node_to_hash(node)
# If we are at the root of the document, start the hash
if node.element?
if node.children?
result_hash = {}
node.each_child do |child|
result = xml_node_to_hash(child)
if child.name == "text"
if !child.next? and !child.prev?
return result
end
elsif result_hash[child.name.to_sym]
if result_hash[child.name.to_sym].is_a?(Object::Array)
result_hash[child.name.to_sym] << result
else
result_hash[child.name.to_sym] = [result_hash[child.name.to_sym]] << result
end
else
result_hash[child.name.to_sym] = result
end
end
return result_hash
else
return nil
end
else
return node.content.to_s
end
end
end
end
Hãy xem xét kết hợp đơn giản mà tôi đã tạo cho nút Nokogiri XML Node.
http://github.com/kuroir/Nokogiri-to-Hash
Dưới đây là một ví dụ sử dụng:
require 'rubygems'
require 'nokogiri'
require 'nokogiri_to_hash'
html = '
<div id="hello" class="container">
<p>Hello! visit my site <a href="http://kuroir.com">Kuroir.com</a></p>
</div>
'
p Nokogiri.HTML(html).to_hash
=> [{:div=>{:class=>["container"], :children=>[{:p=>{:children=>[{:a=>{:href=>["http://kuroir.com"], :children=>[]}}]}}], :id=>["hello"]}}]
Tôi tìm thấy điều này trong khi cố gắng để đơn giản là chuyển đổi XML để Băm (không phải trong Rails). Tôi đã nghĩ rằng tôi sẽ sử dụng Nokogiri, nhưng cuối cùng đã đi với Nori.
Sau đó, mã của tôi là trival:
response_hash = Nori.parse(response)
người dùng khác đã chỉ ra rằng điều này không làm việc. Tôi chưa xác minh, nhưng có vẻ như phương thức phân tích cú pháp đã được di chuyển từ lớp này sang cá thể khác. Mã của tôi ở trên làm việc tại một số điểm. Mới (chưa được xác minh) mã sẽ là:
response_hash = Nori.new.parse(response)
Tôi nghĩ đây là giải pháp tốt nhất cho các ứng dụng không sử dụng Rails. –
Dòng * un * đã xác minh hoạt động. Tuy nhiên, nếu bạn có một tài liệu 'Nokogiri :: XML', trước tiên bạn phải gọi phương thức' to_s' của nó. Ví dụ. 'xml = Nokogiri :: XML (File.open ('file.xml'))' và sau đó 'hash = Nori.new.parse (xml.to_s)', nhưng các trường xuất hiện để được trả về dưới dạng 'Mảng' mà không có tên trường. – ray
Sau khi đập đầu vào tường cố gắng sử dụng Nokogiri, tôi cuối cùng cũng bắt gặp nó. Là BY FAR giải pháp tốt nhất! Cảm ơn vì bài đăng. –
Nếu nút mà bạn đã chọn trong Nokogiri chỉ bao gồm một thẻ, bạn có thể trích xuất các phím, giá trị và nén chúng vào một băm, như vậy:
@doc ||= Nokogiri::XML(File.read("myxmldoc.xml"))
@node = @doc.at('#uniqueID') # this works if this selects only one node
nodeHash = Hash[*@node.keys().zip(@node.values()).flatten]
Xem http://www.ruby-forum.com/topic/125944 để biết thêm thông tin về cách hợp nhất mảng Ruby.
Nếu bạn muốn chuyển đổi một tài liệu XML Nokogiri để băm, chỉ cần làm như sau:
require 'active_support/core_ext/hash/conversions'
hash = Hash.from_xml(nokogiri_document.to_s)
Vui lòng giải thích từ 'from_xml' đến từ đâu. Nó không phải là một phương thức chuẩn của Ruby. –
@theTinMan from_xml đến từ ActiveSupport – ScottJShea
Nó xuất phát từ đây: http://api.rubyonrails.org/classes/Hash.html#method-c-from_xml, mã là: 'typecast_xml_value (unrename_keys (ActiveSupport :: XmlMini.parse (xml))) ' – Dorian
Dưới đây là một phiên bản đơn giản hơn nhiều mà tạo ra một Hash mạnh mẽ bao gồm thông tin không gian tên, cả hai cho các yếu tố và các thuộc tính:
require 'nokogiri'
class Nokogiri::XML::Node
TYPENAMES = {1=>'element',2=>'attribute',3=>'text',4=>'cdata',8=>'comment'}
def to_hash
{kind:TYPENAMES[node_type],name:name}.tap do |h|
h.merge! nshref:namespace.href, nsprefix:namespace.prefix if namespace
h.merge! text:text
h.merge! attr:attribute_nodes.map(&:to_hash) if element?
h.merge! kids:children.map(&:to_hash) if element?
end
end
end
class Nokogiri::XML::Document
def to_hash; root.to_hash; end
end
Seen trong hành động:
xml = '<r a="b" xmlns:z="foo"><z:a>Hello <b z:m="n" x="y">World</b>!</z:a></r>'
doc = Nokogiri::XML(xml)
p doc.to_hash
#=> {
#=> :kind=>"element",
#=> :name=>"r",
#=> :text=>"Hello World!",
#=> :attr=>[
#=> {
#=> :kind=>"attribute",
#=> :name=>"a",
#=> :text=>"b"
#=> }
#=> ],
#=> :kids=>[
#=> {
#=> :kind=>"element",
#=> :name=>"a",
#=> :nshref=>"foo",
#=> :nsprefix=>"z",
#=> :text=>"Hello World!",
#=> :attr=>[],
#=> :kids=>[
#=> {
#=> :kind=>"text",
#=> :name=>"text",
#=> :text=>"Hello "
#=> },
#=> {
#=> :kind=>"element",
#=> :name=>"b",
#=> :text=>"World",
#=> :attr=>[
#=> {
#=> :kind=>"attribute",
#=> :name=>"m",
#=> :nshref=>"foo",
#=> :nsprefix=>"z",
#=> :text=>"n"
#=> },
#=> {
#=> :kind=>"attribute",
#=> :name=>"x",
#=> :text=>"y"
#=> }
#=> ],
#=> :kids=>[
#=> {
#=> :kind=>"text",
#=> :name=>"text",
#=> :text=>"World"
#=> }
#=> ]
#=> },
#=> {
#=> :kind=>"text",
#=> :name=>"text",
#=> :text=>"!"
#=> }
#=> ]
#=> }
#=> ]
#=> }
chỉ là tuyệt vời! –
Nếu bạn Defi ne một cái gì đó như thế này trong cấu hình của bạn:
ActiveSupport::XmlMini.backend = 'Nokogiri'
nó bao gồm một mô-đun trong Nokogiri và bạn có được phương pháp to_hash
.
Sử dụng Nokogiri để phân tích cú pháp phản hồi XML thành băm băm. Nó khá nhanh.
doc = Nokogiri::XML(response_body)
Hash.from_xml(doc.to_s)
'doc.to_s' trả về những gì bạn đã có trong' response_body', vì vậy nokogiri là vô ích trong ví dụ của bạn – alesguzik
@alesguzik là đúng về cơ bản trong câu lệnh đó bạn đang phân tích cú pháp xml hai lần Hash.from_xml sẽ sử dụng REXML theo mặc định không Nokogiri cũng không chắc chắn nếu bạn có thể thay đổi điều này –
Nokogiri đôi khi linh hoạt hơn để phân tích cú pháp XML được tạo hình hoặc mã hóa kém. Tôi có ví dụ nơi Hash.from_xml (xml_str) sẽ thất bại, nhưng điều này vẫn sẽ làm việc. Vì vậy, nó có thể là một dự phòng cho Hash.from_xml (xml_str) – user4887419
Thực ra, Rails 'Hash.from_xml được gói gọn trong phần MiniXML của mã Rails. Tôi đã có ý nghĩa để trích xuất nó kể từ khi tôi viết nó. Hãy cho tôi một cú huých nếu bạn không sớm nghe về nó. –
Có điều gì không phù hợp với 'Hash.from_xml (nokogiri_doc.to_xml)'? – JellicleCat
http://amolnpujari.wordpress.com/2012/03/31/reading_huge_xml-rb/ Tôi tìm thấy bò gấp 5 lần so với nokogiri, do đó ở đây một ví dụ trong ox - https://gist.github.com/amolpujari/5966431 , tìm kiếm bất kỳ phần tử nào và lấy nó ở dạng băm –