Использование регулярных выражений в Java для изменения XML - PullRequest
1 голос
/ 06 марта 2012

Я пытаюсь изменить XML с помощью регулярных выражений в Java, но я не могу найти правильный путь.У меня есть xml вроде этого (упрощенно):

<ROOT>
   <NODE ord="1" />
   <NODE ord="3,2" />
</ROOT>

xml на самом деле показывает предложение с его узлами, кусками ... на двух языках и имеет больше атрибутов.Каждое предложение загружается в два RichTextAreas (одно для исходного предложения, а другое для переведенного).

Что мне нужно сделать, это добавить атрибут стиля к каждому узлу, который имеет определенное значение в своем атрибуте ord (этот атрибут стиля будет отображать соответствия между двумя языками, как это делает Google Translate при наведении курсора на слово),Я знаю, что это можно сделать с помощью DOM (получение всех узлов NODE и затем просмотр атрибута ord один за другим), но я ищу самый быстрый способ внести изменения, поскольку они будут выполняться на стороне клиента моего GWTприложение.

Когда этот атрибут ord имеет единственное значение (как в первом узле), это легко сделать, просто взяв xml в виде строки и используя функцию replaceAll ().Проблема в том, что атрибут имеет составные значения (как во втором узле).

Например, как я могу добавить этот атрибут, если искомое значение равно 2?Я считаю, что это можно сделать с помощью регулярных выражений, но я не могу понять, как это сделать.Будем благодарны за любую подсказку или помощь (даже если она не использует функцию regexp и replaceAll).

Заранее спасибо.

Ответы [ 4 ]

1 голос
/ 06 марта 2012

Я пытаюсь изменить XML с помощью регулярных выражений в Java, но я не могу найти правильный путь.

Это потому, что нет правильного пути. Регулярные выражения не являются правильным способом манипулирования XML. Это потому, что XML - это не обычная грамматика (это технический термин в компьютерной науке, а не обобщенное оскорбление.)

1 голос
/ 06 марта 2012
String resultString = subjectString.replaceAll("<NODE ord=\"([^\"]*\\b2\\b[^\"]*)\" />", "<NODE ord=\"$1\" style=\"whatever\"/>");

найдет любой тег <NODE>, который имеет один атрибут ord со значением "2" (или "1,2" или "2,3" или "1,2,3", но не "12" ") и добавляет атрибут style.

Это быстрое и грязное, и многие здесь справедливо советуются против него, но для одноразовой быстрой работы все должно быть в порядке.

Пояснение:

<NODE ord="  # Match <NODE ord:" verbatim
(            # Match and capture...
 [^"]*       #  any number of characters except "
 \b2\b       #  "2" as a whole word (surrounded by non-alphanumerics)
 [^"]*       #  any number of characters except "
)            # End of capturing group
" />         # Match " /> verbatim
1 голос
/ 06 марта 2012

XPath может сделать это за вас.Вы можете выбрать:

/ROOT/NODE[contains(concat(',', @ord, ','), ',2,')]

Поскольку вы намереваетесь использовать GWT на клиенте, вы можете попробовать gwtxslt .С его помощью вы можете указать таблицу стилей XSLT для выполнения преобразования (т.е. добавления атрибута) для вас:

XsltProcessor processor = new XsltProcessor();
processor.importStyleSheet(styleSheetText);
processor.importSource(sourceText);
processor.setParameter("ord", "2");
processor.setParameter("style", "whatever");
String resultString = processor.transform();
// do something with resultString

, где styleSheetText может быть документом XSLT вдоль строк

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:param name="ord"   select="''" />
  <xsl:param name="style" select="''" />

  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="NODE">
    <xsl:copy>
      <xsl:apply-templates select="@*" />
      <xsl:if test="contains(concat(',', @ord, ','), concat(',', $ord, ','))">
        <xsl:attribute name="style">
          <xsl:value-of select="$style" />
        </xsl:attribute>
      </xsl:if>
      <xsl:apply-templates select="node()" />
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

Обратите внимание, что я использую concat() для предотвращения частичных совпадений в списке через запятую, которым на самом деле является значение атрибута @ord.

0 голосов
/ 06 марта 2012

Это может звучать как излишнее, но я бы подумал о том, чтобы использовать стандартные парсеры DOM для чтения фрагмента, изменить его с помощью вызовов setAttribute (), а затем снова записать его.Я знаю, что вы сказали, что эффективность важна, но сколько времени это действительно займет?Тестирование показывает 60 мс на моем устаревшем 2 ГГц Pentium.

Этот подход будет более устойчивым к комментариям, вещам, разбитым на строки и т. Д. Кроме того, гораздо более вероятно, что вы получите правильно сформированный XML.Также такие вещи, как ваше требование делать это только при наличии определенных значений, станут тривиальными.

public class AddStyleExample {

    public static void main(final String[] args) {
        String input = "<ROOT> <NODE ord=\"1\" /> <NODE ord=\"3,2\" /> </ROOT>";
        try {
            final DocumentBuilderFactory factory = DocumentBuilderFactory
                    .newInstance();
            factory.setValidating(false);
            factory.setNamespaceAware(false);
            DocumentBuilder builder;

            builder = factory.newDocumentBuilder();

            final Document doc = builder.parse(new InputSource(
                    new StringReader(input)));

            NodeList tags = doc.getElementsByTagName("NODE");
            for (int i = 0; i < tags.getLength(); i++) {
                Element node = (Element) tags.item(i);
                node.setAttribute("style", "example value");
            }
            StringWriter writer = new StringWriter();
            final StreamResult result = new StreamResult(writer);
            final Transformer t = TransformerFactory.newInstance()
                    .newTransformer();
            t.setOutputProperty(OutputKeys.INDENT, "yes");
            t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
            t.transform(new DOMSource(doc), result);
            System.out.println(writer.toString());

        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (TransformerException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...