JSoup: замена строки добавляет новые строки - PullRequest
1 голос
/ 18 мая 2011

У меня следующая проблема с JSoup.

Я хочу проанализировать и изменить следующий HTML-код:

<code>
<style type="text/css" media="all">
@import url("http://hakkon-aetterni.at/modules/system/system.base.css?ll3lgd");
@import url("http://hakkon-aetterni.at/modules/system/system.menus.css?ll3lgd");
@import url("http://hakkon-aetterni.at/modules/system/system.messages.css?ll3lgd");
@import url("http://hakkon-aetterni.at/modules/system/system.theme.css?ll3lgd");

  </style> 
</code>

Я использую следующий код для достижения этого:

Elements cssImports= doc.select("style");
        for (Element src : cssImports) {
            String regex ="url\\(\"(.)*\"\\)";
            String data =src.data();
            String link;        

            Pattern p = Pattern.compile(regex);
            Matcher m = p.matcher(data);

            while (m.find()){
                link=m.group().substring(5,m.group().length()-2);
                doc=Jsoup.parse(doc.html().replace(link, ""));
            }
        }

Во-первых, это работает. Все URL-адреса импорта заменяются строкой "FOUND". У меня проблема в том, что я получаю много новых строк между последним оператором импорта и закрытым тегом </style>, которого раньше не было.

Есть какие-нибудь подсказки, почему это происходит, и как мне этого избежать?

Извините за плохое форматирование, но мне кажется, что некоторые части моего кода просто удаляются при публикации. Вокруг первого блока кода есть тег стиля ...

1 Ответ

2 голосов
/ 24 июня 2011

Что ж, я попал на эту страницу сегодня, пытаясь сделать очень похожую вещь, и я верю, что решил ее. Надеюсь, кто-то все еще смотрит это сейчас, через месяц. ;)

То, что я нашел, работало хорошо, вместо того, чтобы выполнять замену строк и повторный анализ документа в каждом цикле, перестраивать содержимое элемента style. Одним из мест, где JSoup действительно блестит, является то, как легко его API упрощает редактирование разобранного документа.

Другой трюк заключается в использовании функции data(). JSoup различает данные (например, script и style) и узлы html / text. Основное отличие состоит в том, что экранирование HTML не применяется к узлам данных.

Собрав все это вместе, следующий фрагмент кода должен заменить ссылки на импортированные таблицы стилей на текст FOUND, но без изменения форматирования документа:

// compile the regex before entering the loop, as it's a relatively expensive operation
Pattern pattern = Pattern.compile("url\\(\"(.)*\"\\)");
for(Element styleElem : doc.getElementsByTag("style")) {

    String data = styleElem.data();
    StringBuffer newData = new StringBuffer();
    Matcher matcher = pattern.matcher(data);

    while(matcher.find()) {
        matcher.appendReplacement(newData, "FOUND");
    }
    matcher.appendTail(newData);

    styleElem.appendChild(new DataNode(newData.toString(), base.toExternalForm()));
}

P.S. Я предполагаю, что вы отключили симпатичную печать. Поскольку ваш код синтаксического анализа документа не отображается, дважды убедитесь, что после синтаксического анализа вызвала document.outputSettings().prettyPrint(false);.

P.P.S. В моем собственном коде я использую более терпимое (и немного более уродливое) регулярное выражение для поиска импорта. Это позволяет пользователю избегать пропуска декларации URL, кавычек, паренов и т. Д., Потому что дикий HTML имеет тенденцию делать все эти вещи. Я объявил это в моем коде следующим образом:

public static final Pattern CSS_IMPORT_PATTERN = Pattern.compile("(@import\\s+(?:url)?\\s*\\(?\\s*['\"]?)(.*?)([\\s'\";,)]|$)");
...