У меня есть таблица HTML, в которой, возможно, отсутствуют или неправильно сформированы значения colspan
:
<table border = "1">
<tbody>
<tr>
<th>A</th> <th>B</th> <th>C</th> <th>D</th>
<th>E</th> <th>F</th> <th>G</th> <th>H</th>
<th>I</th> <th>J</th> <th>K</th> <th>L</th>
<th>M</th> <th>N</th> <th>O</th> <th>P</th>
<th>Q</th> <th>R</th> <th>S</th> <th>T</th>
<th>U</th> <th>V</th> <th>W</th> <th>Y</th>
</tr>
<tr>
<td > 0 </td>
<td colspan = "" > 1 </td>
<td colspan = "0" > 2 </td>
<td colspan = "2" > 3 </td>
<td colspan = "-2" > 4 </td>
<td colspan = "+ 2" > 5 </td>
<td colspan = "+2" > 6 </td>
<td colspan = "*2#%@!" > 7 </td>
<td colspan = "2.7" > 8 </td>
<td colspan = "-2.3" > 9 </td>
<td colspan = "2e1" > 10 </td>
<td colspan = " 2 " > 11 </td>
<td colspan = "2xx" > 12 </td>
<td colspan = "2 3" > 13 </td>
<td colspan = "2" colspan = "3" > 14 </td>
</tr>
</tbody>
</table>
Я хотел бы получить значение colspan
каждого td
, поскольку браузер HTML5 «понял» бы их. В настоящее время я пытаюсь выяснить, что говорит об этом спецификация W3C, но давайте учтем, что результаты, отображаемые при запуске приведенного выше фрагмента, являются моим ожидаемым результатом:
colspan
Значение HTML5
отсутствующий
1
""
1
"0"
1
"2"
2
"-2"
1
"+ 2"
1
"+2"
2
"*2#%@!"
1
"2.7"
2
"-2.3"
1
"2e1"
2
" 2 "
2
"2xx"
2
"2 3"
2
"2"
и "3"
2
Как я могу добиться этого с помощью XPath 3.1?
Я попробовал это выражение XPath:
//td/( (1, @colspan[. castable as xs:double]) => max() => xs:integer() )
Но у него есть несколько проблем, например, преобразование "2e1"
в 20
вместо 2
.
Рассмотрим шаблон регулярного выражения, соответствующий значению, для извлечения символов начальных цифр, игнорируя все символы, начинающиеся с первого нецифрового символа. Тогда успешное совпадение дает ведущее целое число; все остальное дает 1:
//td/(if (matches(@colspan[1],'^\s*\+?[1-9]\d*'))
then replace(@colspan[1], '^\s*\+?(\d+).*$', '$1')
else '1')
Обновление: теперь обрабатывается обновление вопросов, в которое добавлены случаи colspan = "0"
и colspan = "+2"
.
Обновление 2: добавлен [1]
в @colspan
согласно наблюдению Фравадоны о том, что (неправильно сформированные) HTML-таблицы могут иметь несколько атрибутов @colspan
.
@Fravadona: Безумно, что вы встретите два атрибута @colspan
в одном элементе, но реальный мир может быть беспорядочным. Обновлено.
Согласно стандартам W3C и WHATWG, допустимое значение colspan
в терминах регулярного выражения имеет форму ^\s*\+?(\d+).*
, при этом часть в круглых скобках является частью, которую необходимо преобразовать в десятичное число. Оба стандарта возвращаются к 1
, когда colspan
равен нулю, недействителен или отсутствует.
Ответ @kjhughes работает достаточно хорошо, но есть другой способ с analyze-string
и max
:
//td/( max((1, analyze-string(@colspan[1], "^\s*\+?\d+")/fn:match)) )
Вот некоторые важные моменты стандарта W3C:
Если текущая ячейка имеет атрибут
colspan
, то проанализируйте значение этого атрибута и пустьcolspan
будет результатом.Если синтаксический анализ этого значения не удался, или вернул ноль, или если атрибут отсутствует, то вместо этого пусть
colspan
будет1
.
- Если символ, указанный в позиции, представляет собой символ U+002B ПЛЮС ЗНАК (+), перейдите к следующему символу. (Знак «+» игнорируется, но это не соответствует.)
- Соберите последовательность символов в диапазоне от U+0030 ЦИФРА НОЛЬ (0) до U+0039 ЦИФРА ДЕВЯТЬ (9) и интерпретируйте полученную последовательность как целое число с основанием десять. Пусть значение будет этим целым числом.
Пока позиция не указывает за конец ввода, а символ в позиции является одним из символов, добавьте этот символ в конец результата и переместите позицию на следующий символ во вводе.
Красиво и лаконично! И в целом отличная работа с вопросами/ответами. 👍
Рассмотрим сопоставление шаблонов регулярных выражений для нормализованного по пространству значения для извлечения начальных целочисленных символов, игнорируя все символы, начинающиеся с первого нецелого символа. Тогда успешное совпадение дает ведущее целое число; все остальное дает
1
.