Разбор XML с помощью REGEX в Java - PullRequest
       83

Разбор XML с помощью REGEX в Java

3 голосов
/ 02 декабря 2008

Учитывая приведенный ниже фрагмент XML, мне нужно получить список пар имя / значение для каждого дочернего элемента в DataElements. XPath или парсер XML нельзя использовать по независящим от меня причинам, поэтому я использую регулярное выражение.

<?xml version="1.0"?>
<StandardDataObject xmlns="myns">
  <DataElements>
    <EmpStatus>2.0</EmpStatus>
    <Expenditure>95465.00</Expenditure>
    <StaffType>11.A</StaffType>
    <Industry>13</Industry>
  </DataElements>
  <InteractionElements>
    <TargetCenter>92f4-MPA</TargetCenter>
    <Trace>7.19879</Trace>
  </InteractionElements>
</StandardDataObject>

Вывод, который мне нужен: [{EmpStatus: 2.0}, {Расходы: 95465.00}, {StaffType: 11.A}, {Industry: 13}]

Имена тегов в DataElements являются динамическими и поэтому не могут быть выражены буквально в регулярном выражении. Имена тегов TargetCenter и Trace являются статическими и могут быть в регулярном выражении, но если есть способ избежать жесткого кодирования, это было бы предпочтительным.

"<([A-Za-z0-9]+?)>([A-Za-z0-9.]*?)</"

Это регулярное выражение, которое я построил, и проблема в том, что он ошибочно включает {Trace: 719879} в результаты. Полагаться на новые строки в XML или любое другое очевидное форматирование нельзя.

Ниже приведено приблизительное описание используемого Java-кода:

private static final Pattern PATTERN_1 = Pattern.compile(..REGEX..);
private List<DataElement> listDataElements(CharSequence cs) {
    List<DataElement> list = new ArrayList<DataElement>();
    Matcher matcher = PATTERN_1.matcher(cs);
    while (matcher.find()) {
        list.add(new DataElement(matcher.group(1), matcher.group(2)));
    }
    return list;
}

Как я могу изменить свое регулярное выражение, чтобы оно включало только элементы данных и игнорировало остальные?

Ответы [ 8 ]

51 голосов
/ 03 декабря 2008

XML не является обычным языком. Вы не можете проанализировать его с помощью регулярного выражения. Выражение, которое, по вашему мнению, будет работать, сломается, когда вы получите вложенные теги, затем, когда вы исправите это, оно будет разбиваться на комментарии XML, затем на секции CDATA, затем на директивы процессора, затем на пространства имен, ... Это не может работать, используйте синтаксический анализатор XML. 1003 *

13 голосов
/ 03 декабря 2008

Это должно работать в Java, если вы можете предположить, что между тегами DataElements все имеет значение формы. То есть без атрибутов и вложенных элементов.

Pattern regex = Pattern.compile("<DataElements>(.*?)</DataElements>", Pattern.DOTALL);
Matcher matcher = regex.matcher(subjectString);
Pattern regex2 = Pattern.compile("<([^<>]+)>([^<>]+)</\\1>");
if (matcher.find()) {
    String DataElements = matcher.group(1);
    Matcher matcher2 = regex2.matcher(DataElements);
    while (matcher2.find()) {
        list.add(new DataElement(matcher2.group(1), matcher2.group(2)));
    } 
}
4 голосов
/ 02 декабря 2008

Используйте XPath вместо!

2 голосов
/ 02 декабря 2008

Вы действительно должны использовать для этого библиотеку XML.

Если вам нужно использовать RE, почему бы не сделать это в два этапа? DataElements>.*?</DataElements тогда что у тебя сейчас.

1 голос
/ 03 декабря 2008

Вы должны слушать всех. Облегченный парсер - плохая идея.

Однако, если вы действительно так усердны в этом, вы сможете настроить свой код, чтобы исключить теги вне тега DataElements.

private static final Pattern PATTERN_1 = Pattern.compile(..REGEX..);
private static final String START_TAG = "<DataElements>";
private static final String END_TAG = "</DataElements>";
private List<DataElement> listDataElements(String input) {
    String cs = input.substring(input.indexOf(START_TAG) + START_TAG.length(), input.indexOf(END_TAG);
    List<DataElement> list = new ArrayList<DataElement>();
    Matcher matcher = PATTERN_1.matcher(cs);
    while (matcher.find()) {
        list.add(new DataElement(matcher.group(1), matcher.group(2)));
    }
    return list;
}

Это ужасно не получится, если тег dataelements не существует.

Еще раз, это плохая идея, и вы, вероятно, будете в будущем пересматривать этот фрагмент кода в форме отчета об ошибке.

1 голос
/ 03 декабря 2008

Извините, что дал вам еще один ответ "Не используйте регулярные выражения", но серьезно. Пожалуйста, используйте Commons-Digester , JAXP (в комплекте с Java 5+) или JAXB (в комплекте с Java 6+), так как это избавит вас от загрузки лодки причинить боль.

1 голос
/ 02 декабря 2008

Есть ли причина, по которой вы не используете правильный анализатор XML вместо регулярных выражений? Это было бы тривиально с правильной библиотекой.

0 голосов
/ 06 июня 2017

Попробуйте проанализировать Reg Ex через файл свойств и затем создать объект шаблона. Я разобрался с той же проблемой, с которой столкнулся при введении Reg Ex через XML-бины.

Пример: - Мне нужно было проанализировать Reg Ex '(.) (D [0-9] {7} .D [0-9] {9} .D [AZ] {3} [0-9] {4}) (.) 'Путем инъекции весной. Но это не сработало. Однажды попробовал использовать тот же Reg Ex, жестко запрограммированный в классе Java, он работал.

Pattern pattern = Pattern.compile ("(.) (D [0-9] {7} .D [0-9] {9} .D [AZ] {2} [0-9] {4} ) (). "); Matcher matcher = pattern.matcher (file.getName (). Trim ());

Next I tried to load that Reg Ex via property file while injecting it. It worked fine.

  p:remoteDirectory="${rawDailyReport.remote.download.dir}"
  p:localDirectory="${rawDailyReport.local.valid.dir}"
  p:redEx="${rawDailyReport.download.regex}"

А в файле свойств это свойство определяется следующим образом.

rawDailyReport.download.regex = (. ) (D [0-9] {7} \. D [0-9] {9} \. D [AZ] {2} [0-9] {4}) (. )

Это связано с тем, что значения с заполнителями загружаются через org.springframework.beans.factory.config.PropertyPlaceholderConfigurer и обрабатывают эти чувствительные к XML символы внутренне.

Спасибо, Amith

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