Как проверить, есть ли у элемента дублированные атрибуты с помощью cheerio js

1

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

пример частичного файла, который имеет элемент с повторным атрибутом "class":

<div class="logo-center" data-something-very-long="something long" ... class="logo" data-more-stuff>

Вот код, который загружает файл:

var fileContents = fs.readFileSync(file, "utf8");
var $ = cheerio.load(fileContents);

Примечание: он не должен быть атрибутом класса, это может быть любой другой атрибут, который повторяется.

Теги:
cheerio

2 ответа

1
Лучший ответ

Выполните анализ вновь проверяемого элемента. Для этого вам нужно немного погрузиться в необработанный объект DOM, созданный cheerio/htmlparser2. Он использует свойства, которые документированы для domhandler, но не для cheerio, поэтому может потребоваться некоторое обслуживание версий. Я проверил с

└─┬ [email protected] 
  ├─┬ [email protected] 
  │ ├── [email protected] 

Я сформулировал этот стиль ES6, но вы могли бы сделать то же самое, что и с более старыми, более обычными конструкциями.

RegExp может потребоваться некоторое усовершенствование, в зависимости от ваших ожиданий от файлов, которые вы тестируете.

const fileContents = fs.readFileSync(file, "utf8");
const $ = cheerio.load(fileContents, {
  useHtmlParser2: true,
  withStartIndices: true,
  withEndIndices: true
});

function getDuplicateAttributes ($elem) {
    const dom = $elem.get(0);

    // identify tag text position in string
    const start = dom.startIndex;
    const end = dom.children.length ? dom.children[0].startIndex : dom.endIndex + 1;
    // extract
    const html = fileContents.slice(start, end);

    // generator function loops through all attribute matches on the html string
    function* multivals (attr) {
        const re = new RegExp('\\s${attr}="(.*?)"', 'g');
        let match;
        while((match = re.exec(html)) !== null) {
            // yield each property value found for the attr name
            yield match[1];
        }
    }

    // the DOM will contain all attribute names once
    const doubleAttributeList = Object.keys(dom.attribs)
       // compound attribute names with all found values
      .map((attr) => {
           const matchIterator = multivals(attr);
           return [attr, Array.from(matchIterator)];
      })
      // filter for doubles
      .filter((entry) => entry[1].length > 1);

    return new Map(doubleAttributeList);
}

Вы не указали, что хотите делать, если нашли двойники, поэтому они просто вернулись.

  • 0
    Я попробовал, но это не сработало так, как ожидалось, потому что cheerio заранее анализирует HTML, удаляя ненужные атрибуты, например, <div class="my-class" class="my-other-class" data-something="something" data-something-else></div> в <div class="my-class" data-something="something" data-something-else=""></div>
  • 0
    Извините, в коде были действительно глупые ошибки, самая важная из которых - жадный квантификатор для RegEx. Он должен быть записан как new RegExp('\\sclass="(.*?)"', 'g') .
Показать ещё 4 комментария
0

Ответ @ccprog работал, вот небольшой рефактор ES5:

var file = 'some file';
var fileContents = fs.readFileSync(file, 'utf8');
var $ = cheerio.load(fileContents, {
  useHtmlParser2: true,
  withStartIndices: true,
  withEndIndices: true
});

function getDuplicateAttributes ($elem) {
  var dom = $elem.get(0);

  // identify tag text position in fileContents
  var start = dom.startIndex;
  var end = dom.children.length ? dom.children[0].startIndex : dom.endIndex + 1;

  // extract
  var html = fileContents.slice(start, end);

  // the DOM will contain all attribute names once
  return Object.keys(dom.attribs)
    // compound attribute names with all found values
    .map(function (attr) {
      // modify regexp to capture values if needed
      var regexp = new RegExp('\\s' + attr + '[\\s>=]', 'g');
      return html.match(regexp).length > 1 ? attr : null;
    })
    // filter for doubles
    .filter(function (attr) {  
      return attr !== null;
    });
}

var duplicatedAttrs = getDuplicateAttributes($(".some-elem"));

Код:

  • удаляет генератор
  • ES6 - ES5
  • улучшить RegExp
  • используйте string.match() вместо regexp.exec().
  • 0
    Недостатком этого RegExp является то, что вы не узнаете, какие значения были введены для удвоенных атрибутов. (Вы, очевидно, знаете об этом - просто запишите это.)
  • 0
    Это правильно, мне нужно было только знать, какие атрибуты повторяются в HTML.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню