0

我正在尝试将 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 文档。

我该如何去做上面的事情?

4

2 回答 2

2

编辑:

好的,现在我明白这可以跨越标签,我想我理解这里的困难。

我在这里能想到的唯一算法是遍历 XML 树,读取文本部分以搜索您的匹配项——您需要在多个节点上逐个字符地匹配自己。困难当然是在这个过程中不要把树弄脏……

这是我的做法:

创建一个步行器以步行到 XML 树。每当您认为已找到字符串匹配的开始时,请保存当前父节点的任何内容。何时(以及是否)找到字符串匹配的结尾,检查保存的节点是否与结尾节点的父节点相同。如果它们相同,那么修改树是安全的。

示例文档:

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

测试 1:匹配:示例文本

walker 会一直走下去,直到找到示例中的“e”,它会保存父节点(<b>node )并继续行走,直到找到text它会检查它是否仍在同一个参考节点<b>中的终点是的,所以它是匹配的,你可以用它或其他任何东西来标记它。

测试 2:匹配:一个例子

walker 会先点击a并迅速拒绝它,然后点击an并保存<doc>节点。它将继续匹配example文本,直到它意识到该示例的父节点是<b>而不是<doc>此时匹配失败并且没有安装节点。

实施1:

如果您只匹配纯文本,那么使用 Java(SAX 或其他东西)的简单匹配器似乎是一种方法。

实施2:

如果匹配的输入是正则表达式本身,那么您将需要一些非常特别的东西。我知道没有引擎可以肯定在这里工作,你可以做的是写一些丑陋的东西来做......也许某种递归walker会将XML树分解成越来越小的节点-sets,在每个级别搜索完整的文本...

非常粗糙(不工作)的代码:

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

一旦您知道应该包含匹配项的节点在哪里,我不确定可以做什么,因为您不知道如何从正则表达式中找出文本中需要它的索引...也许有人有一个正则表达式,你可以修改......

于 2009-06-23T19:33:58.400 回答
0

我认为“我要匹配的文本将跨越多个标签”的意思是这样的:

 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 也不会对您有所帮助。事实上,我认为没有不涉及编写解析器的第二个问题的答案。

这不是一个真正的答案,我知道。

于 2009-06-25T20:01:44.033 回答