Как изменить XML на основе совпадений регулярных выражений с текстом (символьные данные) - PullRequest
0 голосов
/ 23 июня 2009

Я пытаюсь сопоставить текстовое содержимое (символьные данные) файла XML с рядом регулярных выражений, а затем изменить XML на основе совпадений. Пример:

 <text>
 <para>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
 </para>
 </text>

Я хочу сопоставить, например, следующее регулярное выражение с текстом:

\bdolor.\b

Для каждого совпадения, которое я хочу, например, окружить совпадением с помощью тегов или аналогичных элементов, поэтому приведенное выше превращается в:

<text>
<para>Lorem ipsum <bold>dolor<bold/> sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et <bold>dolore<bold/> magna aliqua.
</para>
</text>

Еще одно осложнение заключается в том, что текст (символьные данные), с которым я хочу сопоставить, может охватывать несколько тегов.

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

Я бы хотел использовать Java (фактически Clojure) для этого, и я намерен использовать JAXB для манипулирования документом XML.

Как мне поступить выше?

Ответы [ 2 ]

2 голосов
/ 23 июня 2009

EDIT:

Хорошо, теперь, когда я понимаю, что это может идти по тегам, я думаю, что я понимаю сложность здесь.

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

Вот как бы я это сделал:

Создайте обходчика, чтобы пройти к дереву XML. Всякий раз, когда вы думаете, что нашли начало совпадения строки, сохраните любой текущий родительский узел. Когда (и если) вы найдете конец вашего совпадения строк, проверьте, совпадает ли сохраненный узел с родительским узлом конечного узла. Если они одинаковы, то модифицировать дерево безопасно.

Пример документа:

<doc>This is a an <b>example text I made up</b> on the spot! Nutty.</doc>

Тест 1: Совпадение: пример текста

Ходок будет идти, пока он не найдет "e" в примере, и он сохранит родительский узел (<b> узел) и продолжит идти, пока не найдет конец text, где он проверит, чтобы увидеть, он все еще находился в том же ссылочном узле <b>, что и есть, так что это совпадение, и вы можете пометить его или как угодно.

Тест 2: Совпадение: пример

Ходок сначала нажмет a и быстро отклонит его, затем нажмет an и сохранит узел <doc>. Он будет продолжать совпадать с текстом example, пока не поймет, что родительский узел этого примера равен <b>, а не <doc>, и в этот момент совпадение не будет выполнено, и ни один узел не будет установлен.

Реализация 1:

Если вы сопоставляете только прямой текст, то простой способ сопоставления, использующий Java (SAX или что-то в этом роде), кажется вам подходящим вариантом.

Реализация 2:

Если соответствующий ввод - это само регулярное выражение, то вам понадобится что-то особенное. Я не знаю ни одного движка, который мог бы работать здесь наверняка, и то, что вы могли бы могли бы сделать, это написать что-то уродливое, чтобы сделать это ... Может быть, какой-то рекурсивный ходок, который сломал бы XML дерево в меньшие и меньшие наборы узлов, ища полный текст на каждом уровне

Очень грубый (нерабочий) код:

def search(raw, regex):
    tree = parseXml(raw)
    text = getText(tree)
    if match(text, regex):


def searchXML(tree, regex):
    text = getFlatText(tree)
    if match(text, regex): # check if this text node might match
        textNodes = getTextNodes(tree)
        for (tn : textNodes): # check if its contained in a single text node
            if match(tn, regex):
                return tn
        xmlnodes = getXMLNodes(tree)
        for (xn : xmlnodes): # check if any of the children contain the text
            match = searchXML(xn, regex)
            if match
                return match
        return tree # matches some combination of text/nodes at this level
                    # but not at a sublevel
    else:
        return None # no match in this subtree

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

0 голосов
/ 26 июня 2009

Я так понимаю, что "текст, с которым я хочу сопоставить, будет охватывать несколько тегов" означает что-то вроде этого:

 In <i>this</i> example, I want to match "In this example".

 In <i><b>this</b></i> example, I also want to match "In this example".

 And <i>in <b>this</b></i> example, it's clear I have to ignore case too.

Это кажется особенно трудной проблемой, потому что преобразование, о котором вы говорите, может привести к тому, что XML не будет правильно сформирован - например, посмотрите, что произойдет, если вы попытаетесь поместить теги вокруг подстроки здесь:

In this <i>example, putting tags around "in this example"</i> will break things.

<i>And in this</i> example, you have a similar problem.

Чтобы получить правильно сформированный вывод, вам, вероятно, понадобится, чтобы он выглядел следующим образом:

<bold>In this <i>example</i><bold><i>, putting tags around "in this example"</i> will break things.

<i>And <bold>in this</bold></i><bold> example</bold>, you have a similar problem.

Теоретически, каждый ваш персонаж может быть в другом элементе:

Almost like <i><u>i</u><u>n</u> </i><u>th</u>is<i><i><u> ex</i>am</i>ple.</i>

Здесь у вас две основные проблемы, и ни одна из них не проста:

  1. Поиск потока XML для подстроки, игнорируя все, что не является текстовым узлом, и возвращает начальную и конечную позиции подстроки в потоке.

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

Мне совершенно ясно, что XSLT и регулярные выражения здесь вам не помогут. Я не думаю, что использование DOM поможет вам и здесь. На самом деле я не думаю, что есть ответ на вторую проблему, которая не связана с написанием парсера.

Это не совсем ответ, я знаю.

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