在java中使用regex来修改xml

时间:2012-03-06 17:26:23

标签: java xml regex gwt

我正在尝试使用java中的正则表达式来更改xml,但我找不到正确的方法。我有一个像这样的xml(简化):

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

xml实际上显示了一个句子,其节点,块......以两种语言显示,并且具有更多属性。每个句子都加载在两个RichTextAreas中(一个用于源语句,另一个用于翻译的句子)。

我需要做的是将样式属性添加到其ord属性中具有特定值的每个节点(此样式属性将显示两种语言之间的对应关系,例如当您将鼠标悬停在单词上时,Google翻译会执行此操作)。我知道这可以使用DOM(获取所有NODE节点,然后逐个查看ord属性)来完成,但我正在寻找最快的方式来进行更改,因为它将在我的GWT的客户端执行应用程序。

当该ord属性具有单个值时(如在第一个节点中),只需将xml作为字符串并使用replaceAll()函数即可。问题是当属性具有组合值时(如在第二个节点中)。

例如,如果我要查找的值是2,我怎么能添加该属性?我相信这可以使用正则表达式完成,但我无法弄清楚如何。任何提示或帮助都会受到赞赏(即使它不使用regexp和replaceAll函数)。

提前致谢。

4 个答案:

答案 0 :(得分:1)

String resultString = subjectString.replaceAll("<NODE ord=\"([^\"]*\\b2\\b[^\"]*)\" />", "<NODE ord=\"$1\" style=\"whatever\"/>");

会找到具有单个<NODE>属性且价值为“2”(或“1,2”或“2,3”或“1,2,3”)的任何ord标记但不是“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 :(得分:1)

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的属性值实际为的部分匹配。

答案 2 :(得分:1)

  

我正在尝试使用java中的正则表达式来更改xml,但我找不到正确的方法。

那是因为没有正确的方法。正则表达式不是操纵XML的正确方法。那是因为XML不是常规语法(这是计算机科学中的技术术语,而不是普遍的侮辱。)

答案 3 :(得分:0)

这可能听起来有些过分,但我会考虑使用标准DOM解析器来读取片段,使用setAttribute()调用对其进行修改,然后再将其写出来。我知道你说效率很重要,但这需要多长时间?测试显示老化的2GHz奔腾60毫秒。

这种方法对于评论,跨行等分割的东西会更强大。它也更有可能为您提供格式良好的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();
        }

    }
}