تحويل مستند Nokogiri إلى تجزئة روبي
-
22-07-2019 - |
سؤال
هل هناك طريقة سهلة لتحويل وثيقة XML Nokogiri إلى تجزئة؟
وشيء من هذا القبيل Hash.from_xml
القضبان ".
المحلول
وأنا استخدم هذا الرمز مع libxml روبي (1.1.3). أنا لم تستخدم nokogiri نفسي، ولكن أنا أفهم أنه يستخدم libxml روبي على أي حال. وأود أيضا أن نشجع لك أن ننظر إلى ROXML ( http://github.com/Empact/roxml/treeو>) التي تقوم بتعيين عناصر XML لروبي الأشياء. أنها بنيت فوق 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
نصائح أخرى
إذا كنت ترغب في تحويل مستند XML Nokogiri إلى تجزئة، تفعل ما يلي:
require 'active_support/core_ext/hash/conversions'
hash = Hash.from_xml(nokogiri_document.to_s)
وهنا صيغة أبسط بكثير يخلق تجزئة قوية يتضمن معلومات مساحة الاسم، سواء بالنسبة للعناصر والصفات:
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
وتواجد في العمل:
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=>"!"
#=> }
#=> ]
#=> }
#=> ]
#=> }
ولقد وجدت هذا في حين تحاول ببساطة تحويل XML إلى تجزئة (وليس في القضبان). كنت أفكر أود أن استخدام Nokogiri، ولكن انتهى الأمر مع نوري .
وبعد ذلك كان قانون بلدي trival:
response_hash = Nori.parse(response)
وأشار
وباقي الأعضاء إلى أن هذا لا يعمل. أنا لم التحقق، ولكن يبدو أن طريقة التحليل قد تم نقله من فئة إلى المثيل. قانون بلدي عملت فوق في مرحلة ما. أن القانون الجديد (لم يتم التحقق منها) على النحو التالي:
response_hash = Nori.new.parse(response)
Nokogiri لتحليل استجابة XML إلى روبي التجزئة. انها سريعة جدا.
doc = Nokogiri::XML(response_body)
Hash.from_xml(doc.to_s)
إذا كنت تعرف شيئا من هذا القبيل في التكوين الخاص بك:
ActiveSupport::XmlMini.backend = 'Nokogiri'
وأنه يتضمن وحدة نمطية في Nokogiri ويمكنك الحصول على طريقة to_hash
.
إذا العقدة التي اخترتها في Nokogiri تتكون من علامة واحدة فقط، يمكنك استخراج مفاتيح وقيم والرمز البريدي لهم في التجزئة واحد، كما يلي:
@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]
http://www.ruby-forum.com/topic/125944 لمزيد من المعلومات حول روبي مجموعة الدمج.
وإلقاء نظرة على هذا المزيج في البسيط الذي أدليت به لNokogiri XML عقدة.
http://github.com/kuroir/Nokogiri-to-Hash
وإليك مثال الاستعمال:
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"]}}]