XPath: как получить текст из этого и следующего тега? - PullRequest
2 голосов
/ 01 августа 2011

У меня есть HTML, как это:

<h1>Hello1</h1>
<p>World1</p>
<h1>Hello2</h1>
<p>World2</p>
<h1>Hello2</h1>
<p>World2</p>

Так что мне нужно получить одновременно Hello1 с World1, Hello2 с World2 и т. Д.

ОБНОВЛЕНИЕ : я использую библиотеку Ruby Mechanize

Ответы [ 2 ]

3 голосов
/ 01 августа 2011

Библиотека Ruby «Механизация» использует библиотеку разбора Nokogiri, поэтому вы можете напрямую вызывать Nokogiri. Одно из возможных решений может выглядеть примерно так:

require 'mechanize'
require 'pp'

html = "<h1>Hello1</h1>
<p>World1</p>
<h1>Hello2</h1>
<p>World2</p>
<h1>Hello2</h1>
<p>World2</p>"

results = []

Nokogiri::HTML(html).xpath("//h1").each do |header|
  p   = header.xpath("following-sibling::p[1]").text
  results << [header.text, p]
end

pp results

EDIT: Этот пример был протестирован с Mechanize v2.0.1, который использует Nokogiri ~ v1.4. Я также протестировал напрямую с Nokogiri v1.5.0 без проблем.

РЕДАКТИРОВАТЬ # 2: Этот пример отвечает на дополнительный вопрос к исходному решению:

require 'nokogiri'
require 'pp'

html = <<HTML
<h1>
<p>
<font size="4">
<b>abide by (something)</b>
</font>
</p>
</h1>
<p>
<font size="3">- to follow the rules of something</font>
</p>
The cleaning staff must abide by the rules of the school.
<br>
<h1>
<p>
<font size="4">
<b>able to breathe easily again</b>
</font>
</p>
</h1>
<p>
My friend was able to breathe easily again when his company did not go bankrupt.
<br>
HTML

doc = Nokogiri::HTML(html)

results = []

Nokogiri::HTML(html).xpath("//h1").each do |header|
  h1   = header.xpath("following-sibling::p/font/b").text
  results << h1
end

pp results

H1 теги с вложенными элементами недопустимы, поэтому Nokogiri исправляет ошибку в процессе анализа. Процесс получения ранее вложенных элементов очень похож на исходное решение.

1 голос
/ 01 августа 2011

Примечание: я остекленел над частью XPath этого запроса.Этот ответ предназначен для таблицы стилей XSLT.

Расширение вашего примера XML для предоставления ему корневого элемента:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <h1>Hello1</h1>
    <p>World1</p>
    <h1>Hello2</h1>
    <p>World2</p>
    <h1>Hello3</h1>
    <p>World3</p>
</root>

Вы можете использовать цикл for-each вместе с "follow-sibling "чтобы получить элементы с чем-то вроде этого:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

    <xsl:output encoding="UTF-8" method="text"/>

    <xsl:template match="/">

        <!-- start lookint for <h1> nodes -->
        <xsl:for-each select="/root/h1">

            <!-- output the h1 text -->
            <xsl:value-of select="."/>

            <!-- print a dash for spacing -->
            <xsl:text> - </xsl:text>

            <!-- select the next <p> node -->
            <xsl:value-of select="following-sibling::p[1]"/>

            <!-- print a new line -->
            <xsl:text>&#10;</xsl:text>

        </xsl:for-each>

    </xsl:template>

</xsl:stylesheet>

Вывод будет выглядеть так:

Hello1 - World1
Hello2 - World2
Hello3 - World3
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...