テキスト(文字データ)に対する正規表現の一致に基づいてXMLを変更する方法
質問
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>
もう1つの複雑な点は、照合するテキスト(文字データ)が複数のタグにまたがることがあることです。
私がやろうとしていることは、テキストの一致する部分を選択して、たとえば一致/選択したテキストの書式を変更する検索を行う場合にワードプロセッサアプリがしなければならないことと非常に似ていると思います。
Java(実際にはClojure)を使用してこれを行いたいので、JAXBを使用してXMLドキュメントを操作するつもりです。
上記のことを行うにはどうすればよいですか
解決
編集:
これでタグ間を移動できることがわかったので、ここでの難しさを理解できたと思います。
ここで考えることができる唯一のアルゴリズムは、XMLツリーを歩いて一致部分を検索するテキスト部分を読み取ることです。複数のノードで文字ごとに一致させる必要があります。もちろん、プロセスでツリーをむちゃにしないことです...
次のようにします:
ウォーカーを作成して、XMLツリーに移動します。文字列の一致の開始点を見つけたと思うときはいつでも、現在の親ノードが何であれ保存してください。文字列の一致が見つかった場合(および一致した場合)、保存されたノードが終了ノードの親と同じかどうかを確認します。それらが同じ場合、ツリーを変更しても安全です。
サンプルドキュメント:
<doc>This is a an <b>example text I made up</b> on the spot! Nutty.</doc>
テスト1: 一致:サンプルテキスト
ウォーカーは、<!> quot; e <!> quot;を見つけるまで歩きます。例では、親ノード(<b>
ノード)を保存し、text
の終わりが見つかるまで歩き続けます。ここで、同じ参照ノードa
にあるかどうかを確認します。一致するため、タグを付けることができます。
テスト2: 一致:例
ウォーカーは最初にan
を押してすぐに拒否し、次に<doc>
を押してexample
ノードを保存します。例の親ノードが<=>ではなく<=>であると認識されるまで、<=>テキストとの照合を続けます。この時点では、照合は失敗し、ノードはインストールされません。
実装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
一致が含まれるノードの場所がわかれば、正規表現から必要なテキスト内のインデックスをどのように把握できるかわからないため、どうすればよいのかわかりません。おそらく誰かが正規表現を持っているので、修正できます...
他のヒント
<!> quot;照合したいテキストは複数のタグにまたがる<!> quot;このようなことを意味します:
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>
ここには基本的に2つの問題がありますが、どちらも単純ではありません:
-
XMLノードのサブストリングを検索し、テキストノード以外のすべてを無視して、ストリーム内のサブストリングの開始位置と終了位置を返します。
-
2つの任意のインデックスをXMLドキュメントに与え、それらのインデックス間でテキストを囲む要素を作成し、タグが2つのインデックスの両方ではなく両方にまたがっている要素を閉じます(そして再び開きます)。
ここでは、XSLTと正規表現が役に立たないことは明らかです。ここでも、DOMの使用が役立つとは思いません。実際、パーサーの作成を伴わない2番目の問題に対する答えはないと思います。
これは実際には答えではありません、私は知っています。