Листовые узлы поиска регулярных выражений плохо отформатированного HTML с использованием Cheerio

У меня есть плохо отформатированный HTML (например, приведенный ниже), и я хочу получить конечные узлы (без дополнительных дочерних элементов), текст которых соответствует заданному регулярному выражению:

<html>
  <head>
    <title>co20140725-ex99_1.htm</title>
  </head>
  <body bgcolor="#ffffff" style="DISPLAY: inline; FONT-FAMILY: Times New Roman; FONT-SIZE: 10pt">
  <div>
  <div style="TEXT-ALIGN: left">&#160;</div>
  <div style="TEXT-ALIGN: right">EXHIBIT 99.1</div>
  <div style="TEXT-ALIGN: left">&#160;</div>
  <div style="TEXT-ALIGN: left">
  <div style="TEXT-INDENT: 0pt; DISPLAY: block; MARGIN-LEFT: 0pt; MARGIN-RIGHT: 0pt" align="left">
  <div style="TEXT-ALIGN: center"><font style="FONT-WEIGHT: bold">ANNOUNCES</font></div>
</html>

Я использую cheerio, который по существу реализует API обхода jQuery. Что я пробовал до сих пор:

  1. Селектор :contains не поддерживает регулярные выражения и даже текст без учета регистра:

    var text = $('body').filter(':contains("ANNOUNCES")');
    
  2. each, затем стандартный JavaScript match:

    $('body').each(function (i, elem) {
      if ($(this).text().match(/announces/i)) {
        var text = $(this).text();
      }
    }
    
  3. children, но выводит одну строку, которая представляет собой весь текст в HTML:

    $('p, b, div, font').children(':contains("string I\'m looking for but this isn\'t case-sensitive like match is")').children().first().text();  
    

Я считаю, что проблема заключается в том, что существует переменное количество вложенных дочерних элементов, и по какой-то причине я получаю все элементы, но у каждого из них есть куча дочерних элементов, и я не мог просто перебирать их и протестировать текст.

Вот что  мой объект выглядит как

Вы можете видеть, что существует множество элементов с переменной вложенностью, и обычно .find() будет работать для поиска по всем элементам в <body>, но .find() и .filter() в этом случае вообще не работают.

Любые мысли о том, как я могу регулярно искать текст в этом HTML?

Полный пример HTML можно найти здесь.


person JohnAllen    schedule 28.07.2014    source источник


Ответы (1)


После уточнения вопрос состоит из двух частей:

  1. Получить только лист узлы, то есть те, которые не имеют собственных дочерних элементов, но содержат только нужный вам текст. Это позволит избежать проблем, с которыми вы столкнулись при третьем подходе с использованием children. Есть два способа сделать это:

    • the *:not(:has('*')) selector
    • выбор всех элементов ('*'), затем фильтрация узлов, у которых нет дочерних элементов. Это в несколько раз быстрее, чем популярный метод сложных селекторов.
  2. Отфильтруйте листовые узлы для тех, чье textContent соответствует вашему регулярному выражению.

Вот код:

$('*').map(function() {
  if (this.children.length) return null;
  if (this.textContent.match(/N/)) return this.textContent;
});

Вот JSBin. (не обращайте внимания на window.runnerWindow.proxyConsole посторонний вывод; это JSBin артефакт.)

person Dan Dascalescu    schedule 28.07.2014