Я разбираю файлы 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);
Примечание: он не должен быть атрибутом класса, это может быть любой другой атрибут, который повторяется.
Выполните анализ вновь проверяемого элемента. Для этого вам нужно немного погрузиться в необработанный объект 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);
}
Вы не указали, что хотите делать, если нашли двойники, поэтому они просто вернулись.
Ответ @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"));
Код:
<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>
new RegExp('\\sclass="(.*?)"', 'g')
.