سؤال

وأود أن يجدوا طريقة للوصول الى نتيجة HTML (المذكورة أدناه) باستخدام التعليمات البرمجية التالية روبي و <لأ href = "http://github.com/tenderlove/nokogiri/tree/master "يختلط =" نوفولو noreferrer "> Nokogiri :

require 'rubygems'
require 'nokogiri'

value = Nokogiri::HTML.parse(<<-HTML_END)
  "<html>
    <body>
      <p id='1'>A</p>
      <p id='2'>B</p>
      <h1>Bla</h1>
      <p id='3'>C</p>
      <p id='4'>D</p>
      <p id='5'>E</p>
    </body>
  </html>"
HTML_END

# The selected-array is given by the application.
# It consists of a sorted array with all ids of 
# <p> that need to be enclosed by the <div>
selected = ["2","3","4"]
first_p = selected.first
last_p = selected.last

#
# WHAT RUBY CODE DO I NEED TO INSERT HERE TO GET
# THE RESULTING HTML AS SEEN BELOW?
#

ووHTML الناتجة يجب أن تبدو هذه (يرجى ملاحظة <div id='XYZ'> إدخالها):

<html>
  <body>
    <p id='1'>A</p>
    <div id='XYZ'>
      <p id='2'>B</p>
      <h1>Bla</h1>
      <p id='3'>C</p>
      <p id='4'>D</p>
    </div>
    <p id='5'>E</p>
  </body>
</html>
هل كانت مفيدة؟

المحلول 2

وهذا هو الحل العامل الأول قد نفذت في مشروعي (فلاد @ SO والبيضاء @ المركز # rubyonrails: شكرا لمساعدتكم والإلهام):

require 'rubygems'
require 'nokogiri'

value = Nokogiri::HTML.parse(<<-HTML_END)
  "<html>
    <body>
      <p id='1'>A</p>
      <p id='2'>B</p>
      <h1>Bla</h1>
      <p id='3'>C</p>
      <p id='4'>D</p>
      <p id='5'>E</p>
    </body>
  </html>"
HTML_END

# The selected-array is given by the application.
# It consists of a sorted array with all ids of 
# <p> that need to be enclosed by the <div>
selected = ["2","3","4"]

# We want an elements, not nodesets!
# .first returns Nokogiri::XML::Element instead of Nokogiri::XML::nodeset
first_p = value.css("p##{selected.first}").first
last_p = value.css("p##{selected.last}").first
parent = value.css('body').first

# build and set new div_node
div_node = Nokogiri::XML::Node.new('div', value)
div_node['class'] = 'XYZ'

# add div_node before first_p
first_p.add_previous_sibling(div_node)

selected_node = false

parent.children.each do |tag|
  # if it's the first_p
  selected_node = true if selected.include? tag['id']
  # if it's anything between the first_p and the last_p
  div_node.add_child(tag) if selected_node
  # if it's the last_p
  selected_node = false if selected.last == tag['id']
end

puts value.to_html

نصائح أخرى

في مثل هذه الحالات عادة تريد استخدام أي SAX اجهة العروض مكتبة الأساسية لكم، لاجتياز وإعادة كتابة XML الإدخال (أو XHTML) statefully ومتسلسل:

require 'nokogiri'
require 'CGI'

Nokogiri::XML::SAX::Parser.new(
  Class.new(Nokogiri::XML::SAX::Document) {
    def initialize first_p, last_p
      @first_p, @last_p = first_p, last_p
    end

    def start_document
      puts '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">'
    end

    def start_element name, attrs = []
      attrs = Hash[*attrs]
      @depth += 1 unless @depth.nil?
      print '<div>' if name=='p' && attrs['id'] == @first_p
      @depth = 1    if name=='p' && attrs['id'] == @last_p && @depth.nil?
      print "<#{ [ name, attrs.collect { |k,v| "#{k}=\"#{CGI::escapeHTML(v)}\"" } ].flatten.join(' ') }>"
    end

    def end_element name
      @depth -= 1 unless @depth.nil?
      print "</#{name}>"
      if @depth == 0
        print '</div>'
        @depth = nil
      end
    end

    def cdata_block string
      print "<![CDATA[#{CGI::escapeHTML(string)}]]>"
    end

    def characters string
      print CGI::escapeHTML(string)
    end

    def comment string
      print "<!--#{string}-->"
    end
  }.new('2', '4')
).parse(<<-HTML_END)
  <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
  <html>
    <body>
      <!-- comment -->
      <![CDATA[
        cdata goes here
      ]]>
      &quot;special&quot; entities 
      <p id="1">A</p>
      <p id="2">B</p>
      <p id="3">C</p>
      <p id="4">D</p>
      <p id="5">E</p>
      <emptytag/>
    </body>
  </html>
HTML_END

وبدلا من ذلك، يمكنك أيضا استخدام DOM اجهة نموذج (وبدلا من واجهة SAX) لتحميل المستند بأكمله في الذاكرة (في بنفس الطريقة التي بدأت تفعل في سؤالك الأصلي)، ثم قم بإجراء التلاعب عقدة (الإدراج وإزالة) على النحو التالي:

require 'rubygems'
require 'nokogiri'

doc = Nokogiri::HTML.parse(<<-HTML_END)
  <html>
    <body>
      <p id='1'>A</p>
      <p id='2'>B</p>
      <p id='3'>C</p>
      <p id='4'>D</p>
      <p id='5'>E</p>
    </body>
  </html>
HTML_END

first_p = "2"
last_p = "4"

doc.css("p[id=\"#{first_p}\"] ~ p[id=\"#{last_p}\"]").each { |node|
  div_node = nil
  node.parent.children.each { |sibling_node|
    if sibling_node.name == 'p' && sibling_node['id'] == first_p
      div_node = Nokogiri::XML::Node.new('div', doc)
      sibling_node.add_previous_sibling(div_node)
    end
    unless div_node.nil?
      sibling_node.remove
      div_node << sibling_node
    end
    if sibling_node.name == 'p' && sibling_node['id'] == last_p
      div_node = nil
    end
  }
}

puts doc
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top