1

次のような構造の HTML ドキュメントがあります。

<li class="indent1">(something)
  <li class="indent2">(something else)</li>
  <li class="indent2">(something else)
    <li class="indent3">(another sublevel)</li>
  </li>
  <li class="indent2">(something else)</li>
</li>

私がする必要があるのは、これらの LI タグを OL タグでラップすることです。ドキュメント全体に、このようなリストが多数あります。HTML は次のようにする必要があります。

<ol>
  <li>(something)
    <ol>
      <li>(something else)</li>
      <li>(something else)
        <ol>
          <li>(another sublevel)</li>
        </ol>
      </li>
      <li>(something else)</li>
    </ol>
  </li>
</ol>

ノコギリでこれを行うにはどうすればよいですか?よろしくお願いします。

編集:

元のドキュメントにある HTML の例を次に示します。私のスクリプトは、すべての P タグを LI タグに変換しました。

  <p class="indent1"><i>a.</i> This regulation describes the Army Planning, Programming,
  Budgeting, and Execution System (PPBES). It explains how an integrated Secretariat and
  Army Staff, with the full participation of major Army commands (MACOMs), Program
  Executive Offices (PEOs), and other operating agencies--</p>

  <p class="indent2">(1) Plan, program, budget, and then allocate and manage approved
  resources.</p>

  <p class="indent2">(2) Provide the commanders in chief (CINCs) of United States unified
  and specified commands with the best mix of Army forces, equipment, and support
  attainable within available resources.</p>

  <p class="indent1"><i>b.</i> The regulation assigns responsibilities and describes
  policy and procedures for using the PPBES to:</p>

インデント 1 クラスは第 1 レベルのリスト項目を意味し、インデント 2 は第 2 レベルを意味します。これらのインデント クラスを適切な順序付きリストに変換する必要があります。

4

2 に答える 2

1

<li>次の解決策は、ドキュメント内のそれぞれと次のいずれかをループすることで機能します。

  • 前にない場合は、新しいものと<ol>交換してから、中に入れてください。<li><li>
  • 直前にある場合は、<ol>これをその中に移動<li>します。
document.css('li').each do |li|
  if li.at_xpath('preceding-sibling::node()[not(self::text()[not(normalize-space())])][1][self::ol]')
    li.previous_element << li
  else
    li.replace('<ol/>').first << li
  end
end

これがテスト済みです。

require 'nokogiri'

# Use XML instead of HTML fragment due to problems with XPath
fragment = Nokogiri::XML.fragment '
  <li>List 1
    <li>List 1a</li>
    <li>List 1b
      <li>List 1bi</li>
    </li>
    <li>List 1c</li>
    New List
    <li>New List 1a</li>
  </li>
  <p>Break 1</p>
  <li>List 2a</li>
  <li>List 2b</li>
  <p>Break 2</p>
  <li>List 3 <li>List 3a</li></li>
'

fragment.css('li').each do |li|
  # Complex test to see if the preceding element is an <ol> and there's no non-empty text the li and it
  # See http://stackoverflow.com/q/14045519/405017
  if li.at_xpath('preceding-sibling::node()[not(self::text()[not(normalize-space())])][1][self::ol]')
    li.previous_element << li
  else
    li.replace('<ol/>').first << li
  end
end

puts fragment   # I've normalized the whitespace in the output to make it clear
#=> <ol>
#=>   <li>List 1
#=>     <ol>
#=>       <li>List 1a</li>
#=>       <li>List 1b
#=>         <ol>
#=>           <li>List 1bi</li>
#=>         </ol>
#=>       </li>
#=>       <li>List 1c</li>
#=>     </ol>
#=>     New List
#=>     <ol><li>New List 1a</li></ol>
#=>   </li>
#=> </ol>
#=> <p>Break 1</p>
#=> <ol>
#=>   <li>List 2a</li>
#=>   <li>List 2b</li>
#=> </ol>
#=> <p>Break 2</p>
#=> <ol>
#=>   <li>List 3
#=>     <ol>
#=>       <li>List 3a</li>
#=>     </ol>
#=>   </li>
#=> </ol>
于 2012-12-26T16:03:12.027 に答える
-1

問題は、html の形式が正しくないことです。nokogiri ではうまく解析できません。

于 2012-12-27T11:09:00.500 に答える