2015-11-20 5 views
1

Мы получаем XML-строку, в которой нам нужно дезинфицировать только одно значение атрибута перед его развязыванием. Проблема в том, что xml очень слабо напечатан и нет гарантии, что атрибуты будут в каком-то определенном порядке или даже присутствовать.Поиск шаблона регулярных выражений для дезинфекции частей XML-строки

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

В этой строке мне нужно вызвать шаблон таким образом, что я только принять строку для значения атрибута XML-, в закодировать любые специальные символы (StringEscapeUtils.escapeXml()) и заменить его значение. Даже если значение содержит строку «значение» внутри, не должно вызывать несоответствия шаблона регулярного выражения.

Пожалуйста, помогите.

+3

Применение регулярного выражения к XML (или аналогичные нерегулярные области проблем) является реприемником для катастрофы. Лучше использовать синтаксический анализатор XML. – Thomas

+0

Спасибо @Thomas, но синтаксические анализаторы xml либо не сработают, либо пройдут синтаксический анализ переданной строки. Мне нужно сделать, чтобы избежать каких-либо специальных символов в атрибуте value, а затем проанализировать его. У вас есть пример, который я могу использовать, который показывает его без использования регулярных выражений? – Ashish

+4

Если XML, который вы получаете, действительно так дерьмово, что вам трудно найти регулярное выражение, которое работает во всех случаях (предположим, что это 'имя =" значение = "и т. Д.). Поэтому, если XML недействителен и, следовательно, приводит к сбою синтаксических анализаторов, я сначала попытаюсь поговорить с отправителем. – Thomas

ответ

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.

0

Мне пришлось сделать что-то подобное в недавнем прошлом (то есть закодировать специальные символы, чтобы позволить маркеру/парсеру выполнять свою работу). Решение, которое я придумал следующий:

  • использования потокового парсер (я использовал woodstox)
  • Дайте ПОТОКОВЫЙ анализатор обычай java.io.FilterReader
  • Реализацию read метода, FilterReader, так что он кодирует специальные символы, когда они читают, то есть что-то вроде этого:

    @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, поэтому такое же решение может применяться и в случае, если вы не хотите/не должны использовать синтаксический анализатор.

Смежные вопросы