寻找正则表达式模式来清理XML字符串的一部分

时间:2015-11-20 09:04:44

标签: java regex xml

我们收到一个XML String,我们需要在解组之前清理一个属性值。问题是xml的类型非常松散,并且无法保证属性将以任何特定顺序存在或甚至存在。

<message>
 <set name=".." value="garbled string" type="name" />
 <set age=".." value="32" />
 <set something=".." value="value=\"\"\"\"" />
 ..
</message>

在这个String中我需要调用一个模式,这样我只需要获取XML的value属性的字符串,编码任何特殊字符(StringEscapeUtils.escapeXml())并替换它的值。即使值包含字符串&#34;值&#34;里面不应该导致任何正则表达式模式不匹配。

请帮忙。

2 个答案:

答案 0 :(得分:0)

您可以将正则表达式(?<=value\=")(?:[^"\\<]|\\"|\\\\)++(?=")Matcher#find()结合使用,以查找XML属性value的所有值。

String input = "<message>\n <set name=\"..\" value=\"garbled string\" type=\"name\" />\n <set age=\"..\" value=\"32\" />\n <set something=\"..\" value=\"value=\\\"\\\"\\\"\\\"\" />\n ..\n</message>";
Pattern pattern = Pattern.compile("(?<=value\\=\")(?:[^\"\\\\<]|\\\\\"|\\\\\\\\|\\\\<)++(?=\")");
Matcher matcher = pattern.matcher(input);
StringBuilder convertedInput = new StringBuilder();

int trailing = 0;
while (matcher.find()) {
    String value = matcher.group();
    String convertedValue = StringEscapeUtils.escapeXml(value);

    convertedInput.append(input.substring(trailing, matcher.start()));
    convertedInput.append(convertedValue);

    trailing = matcher.end();
}

if (trailing < input.length()) {
    convertedInput.append(input.substring(trailing, input.length()));
}

System.out.println(convertedInput);

运行时,convertedInput应包含input - 具体取决于StringEscapeUtils#escapeXml(String)的功能 - 每个value属性的所有值都是转义的XML字符串。我将<添加到没有反斜杠转义的值中不得包含的字符中,否则,name="value="等属性(感谢@Thomas将其指向注释中)会导致正则表达式去干草。

有关使用的正则表达式的详细信息,请访问this链接。

答案 1 :(得分:0)

我最近必须做类似的事情(即编码特殊字符以便让unmarshaller / parser完成它的工作)。我想出的解决方案如下:

  • 使用流解析器(我使用woodstox
  • 为流式解析器提供自定义java.io.FilterReader
  • 实施FilterReader的read方法,以便在读取特殊字符时对其进行编码,例如:

    @Override
    public int read(char[] cbuf, int off, int len) throws IOException {
    
        int charsWithoutEntity = len / 4;
        int read = super.read(myBuffer, off, charsWithoutEntity <= myBuffer.length ? charsWithoutEntity : myBuffer.length);
        int j = 0;
    
        for (int i = 0; i < read; i++, j++) {
    
            cbuf[j] = myBuffer[i];
            if (myBuffer[i] == '&') {
                cbuf[++j] = 'a';
                cbuf[++j] = 'm';
                cbuf[++j] = 'p';
                cbuf[++j] = ';';
            }
        }
    
        return read > 0 ? j : read;
    } 
    

我选择流解析器的原因与此问题无关,我非常确定您可以将FilterReader提供给JAXB Unmarshaller,因此相同的解决方案可能也适用于您不想/需要使用解析器的情况。