Преобразуйте Iterator в цикл for с индексом, чтобы пропустить объекты

Я использую Jericho HTML Parser для разбора искаженного HTML. В частности, я пытаюсь получить все текстовые узлы, обработать текст и затем заменить его.

Я хочу пропустить определенные элементы из обработки. Например, я хочу пропустить все элементы и любой элемент, имеющий атрибут class="noProcess". Итак, если у div есть class = "noProcess", то я хочу пропустить этот div и все дочерние элементы из обработки. Однако я хочу, чтобы эти пропущенные элементы возвращались к выводу после обработки.

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

private String doProcessHtml(String html) {
        Source source = new Source(html);
        OutputDocument outputDocument = new OutputDocument(source);

        for (Segment segment : source) {
            if (segment instanceof Tag) {
                Tag tag = (Tag) segment;
                System.out.println("FOUND TAG: " + tag.getName());

                // DO SOMETHING HERE TO SKIP ENTIRE ELEMENT IF IS <A> OR CLASS="noProcess"

            } else if (segment instanceof CharacterReference) {
                CharacterReference characterReference = (CharacterReference) segment;
                System.out.println("FOUND CHARACTERREFERENCE: " + characterReference.getCharacterReferenceString());
            } else {
                System.out.println("FOUND PLAIN TEXT: " + segment.toString());
                outputDocument.replace(segment, doProcessText(segment.toString()));
            }
        }

       return outputDocument.toString();
    }

Это не похоже на то, что использование метода ignoreWhenParsing() работает для меня, так как анализатор просто обрабатывает "игнорируемый" элемент как текст.

Я думал, что если бы я мог преобразовать цикл Iterator в цикл for (int i = 0;...), я мог бы, вероятно, пропустить элемент и все его дочерние элементы, изменив i так, чтобы он указывал на EndTag, а затем продолжил петля.... но не уверен.

3 ответа

Это должно работать.

String skipTag = null;
for (Segment segment : source) {
    if (skipTag != null) { // is skipping ON?
        if (segment instanceof EndTag && // if EndTag found for the
            skipTag.equals(((EndTag) segment).getName())) { // tag we're skipping
            skipTag = null; // set skipping OFF
        }
        continue; // continue skipping (or skip the EndTag)
    } else if (segment instanceof Tag) { // is tag?
        Tag tag = (Tag) segment;
        System.out.println("FOUND TAG: " + tag.getName());
        if (HTMLElementName.A.equals(tag.getName()) { // if <a> ?
            skipTag = tag.getName(); // set
            continue; // skipping ON
        } else if (tag instanceof StartTag) {
            if ("noProcess".equals( // if <tag class="noProcess" ..> ?
                    ((StartTag) tag).getAttributeValue("class"))) {
                skipTag = tag.getName(); // set
                continue; // skipping ON
            }
        }
    } // ...
}

Удалось получить рабочее решение с помощью метода getEnd() объекта Element тега. Идея состоит в том, чтобы пропустить элементы, если их конечная позиция меньше заданной вами позиции. Таким образом, вы находите конечную позицию элемента, который хотите исключить, и не обрабатываете ничего до этой позиции:

final ArrayList<String> excludeTags = new ArrayList<String>(Arrays.asList(new String[] {"head", "script", "a"}));
final ArrayList<String> excludeClasses = new ArrayList<String>(Arrays.asList(new String[] {"noProcess"}));

Source.LegacyIteratorCompatabilityMode = true;
Source source = new Source(htmlToProcess);
OutputDocument outputDocument = new OutputDocument(source);

int skipToPos = 0;
for (Segment segment : source) {
    if (segment.getBegin() >= skipToPos) {
        if (segment instanceof Tag) {
            Tag tag = (Tag) segment;
            Element element = tag.getElement();

            // check excludeTags
            if (excludeTags.contains(tag.getName().toLowerCase())) {
                skipToPos = element.getEnd();
            }

            // check excludeClasses
            String classes = element.getAttributeValue("class");
            if (classes != null) {
                for (String theClass : classes.split(" ")) {
                    if (excludeClasses.contains(theClass.toLowerCase())) {
                        skipToPos = element.getEnd();
                    }
                }
            }

        } else if (segment instanceof CharacterReference) { // for future use. Source.LegacyIteratorCompatabilityMode = true;
            CharacterReference characterReference = (CharacterReference) segment;
        } else {
            outputDocument.replace(segment, doProcessText(segment.toString()));
        }
    }
}

return outputDocument.toString();

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

for (Segment segment : source) {
        if (segment instanceof Tag) {
            Tag tag = (Tag) segment;
            System.out.println("FOUND TAG: " + tag.getName());

            // DO SOMETHING HERE TO SKIP ENTIRE ELEMENT IF IS <A> OR CLASS="noProcess"
            continue;

        } else if (segment instanceof CharacterReference) {
            CharacterReference characterReference = (CharacterReference) segment;
            System.out.println("FOUND CHARACTERREFERENCE: " + characterReference.getCharacterReferenceString());
            for(Segment child : segment.childNodes()) {
                //Use recursion to process child elements
                //You will want to put your for loop in a separate method so it can be called recursively.
            }
        } else {
            System.out.println("FOUND PLAIN TEXT: " + segment.toString());
            outputDocument.replace(segment, doProcessText(segment.toString()));
        }
    }

Без большего количества кода для проверки трудно определить, возможна ли реструктуризация сегмента элемента или стоит усилий.

Другие вопросы по тегам