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

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

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

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

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, а затем продолжил петля.... но не уверен.


person user2287359    schedule 27.06.2013    source источник
comment
как насчет использования ключевого слова continue?   -  person sanbhat    schedule 27.06.2013
comment
Я мог бы использовать continue, но следующий сегмент будет следующим дочерним элементом элемента, который я хочу пропустить. Как это работает, итератор возвращает все сегменты. Мне нужно что-то, что говорит: EndTag элемента, который вы хотите пропустить, находится в позиции X. Так что перейдите в позицию X и продолжите   -  person user2287359    schedule 27.06.2013


Ответы (3)


Я думаю, вы, возможно, захотите изменить способ построения ваших сегментов. Есть ли способ проанализировать 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()));
        }
    }

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

person ryandlf    schedule 27.06.2013

Удалось получить рабочее решение с помощью метода 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();
person user2287359    schedule 27.06.2013

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

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
            }
        }
    } // ...
}
person Ravi K Thapliyal    schedule 27.06.2013
comment
продолжить не получится. Он не пропускает весь элемент. Он просто пропускает конкретный объект тега. - person user2287359; 27.06.2013