XPath式からドキュメントルートへのすべての参照を抽出し、それらの後にカスタムルートを挿入したいと思います。
スキーマ言語に基づいて作成されたXMLインスタンスドキュメントの検証の小さな部分を実装しています(またはバグを修正しています)。この言語は、自己完結型のXMLチャンクを指定する手段を提供します。このような各チャンクは個別のファイル内で定義され、XML要素の階層を指定します。このような各階層には、XMLドキュメントの非表示のドキュメントルートと同様に、同じドキュメントルートに属する1つ以上のルート要素があります。
ただし、これらのファイルは、それらが指定するものが、より大きなシステムの一部にすぎないという事実を認識していません。この大規模なシステムは、実際には、単一のトップレベルXML要素を持つ別のXMLドキュメント(別のドキュメントルートを持つ)であり、このようなスキーマ言語ファイルの任意の数によって定義されたすべてのルート要素が含まれます。
XML階層内の任意のノードは、検証中に要素が有効であると見なされるためにtrueと評価される必要があるXPath式で制約される場合があります。ここに私の問題の根源があります。これらのXPath式には、システムのドキュメントルートではなく、単一のXMLチャンクのドキュメントルートを参照する絶対ロケーションパスが含まれる場合があります。次のXMLインスタンスについて考えてみます。
<data xmlns="system:uri">
<root-one xmlns="root-one:uri">
<items>
<item>
<group>base</group>
<class>person</person>
<name>John Smith</name>
<description>valid entry</description>
</item>
<item>
<group>base</group>
<class>animal</person>
<name>Dog</name>
<description>invalid entry</description>
</item>
</items>
<item-classes>
<item-class>
<class>person</class>
<group>base</group>
</item-class>
</item-classes>
</root-one>
<root-two xmlns="root-two:uri">
<!-- obscured content -->
</root-two>
</data>
{system:uri}data
システムを表し、 XMLの2つのチャンクで{root-one:uri}root-one
あり{root-two:uri}root-two
、それぞれが独自のスキーマ言語ファイル内で定義されています。root-one/items/item
各インスタンスは、スキーマ言語ファイル内で定義された次のXPath条件を満たす必要があるとしましょう(インスタンスcurrent()
の1つを参照して、XSLTの場合と同じように機能しitem
ます)。
context: /root-one/items/item
assert: group=/root-one/item-classes/item-class[class=current()/class]/group
これは実際には
context: /data/root-one/items/item
assert: group=/data/root-one/item-classes/item-class[class=current()/class]/group
XPath式のドキュメントルート(/)へのすべての参照を取得し、正しいルートを挿入するにはどうすればよいですか?これらの式がどのように形成されるかを制御することはできないため、XPath 1.0構文を満たしている限り、どのような形やサイズでもかまいませんが、適切に評価する必要があります。
私は現在、これを処理するためにJavaである種のトークナイザーを作成することを考えていますが、より単純な解決策がある場合は、それを使用したくありません。式は、システムドキュメントのコンテキスト内でSchematron XSLT変換中に評価されるため、XSLTを使用してパス修正を何らかの方法で実現できれば、それは完璧です。しかし、私は解決策につながる可能性のあるすべてのポインタを受け入れる準備ができています。
Edit01
これは、XPath式を含むサンプルファイルがどのように見えるかを示しています(頭のてっぺんから)。@test
属性の内容を変換したい。属性の値は@context
、常に同様の構造を持っているため、変更するのは簡単です。
<?xml version="1.0" encoding="utf-8"?>
<iso:schema xmlns="http://purl.oclc.org/dsdl/schematron"
xmlns:iso="http://purl.oclc.org/dsdl/schematron"
xmlns:sch="http://www.ascc.net/xml/schematron"
xmlns:tl="toplevel:uri"
xmlns:r1="root-one:uri"
xmlns:r2="root-two:uri">
<iso:ns prefix="tl" uri="toplevel:uri" />
<iso:ns prefix="r1" uri="root-one:uri" />
<iso:ns prefix="r2" uri="root-two:uri" />
<iso:pattern>
<iso:rule context="/r1:root-one/r1:items/r1:item">
<iso:assert test="r1:group=/r1:root-one/r1:item-classes/r1:item-class[r1:class=current()/r1:class]/r1:group">The group of an item must match one of the predefined class groups.</iso:assert>
</iso:rule>
</iso:pattern>
</iso:schema>
@test
属性の値は、任意の有効なXPath1.0式である可能性があることに注意してください。式内の任意の場所で定義された任意のドキュメントルート('/')を検索し、カスタムルート要素を挿入できる汎用ソリューションを使用したいと思います。実際のファイルには、任意の数のiso:pattern
要素、iso:rule
要素などを含めることができます。
Edit02
上記の例では、必要な結果は次のiso:assert
要素です。
<iso:assert test="r1:group=/tl:data/r1:root-one/r1:item-classes/r1:item-class[r1:class=current()/r1:class]/r1:group">The group of an item must match one of the predefined class groups.</iso:assert>
Edit03
/ r1:root-one/の前に「/tl:data」を付ける必要があるとどのように判断しますか?ルールを教えてください。– Dimitre Novatchev
/tl:data
他の複数のXMLドキュメントを1つに結合することによって作成されるドキュメントのルート要素を表します。これらのドキュメントのコンテンツは、このルート要素に子として追加されます。r1:root-one
そのような子の一人になります。の要素構造がどのr1:root-one
ように見えるかを記述するスキーマ定義の一部であるXPath制約は、このサブXMLドキュメントのコンテキストでのみ機能するように設計されています。サブXMLドキュメントが「親」ドキュメントに追加されると、式内に絶対パスが存在する場合、サブXMLドキュメントは意味を失います。したがって、式に含まれている場合、/r1:root-one
これは新しいドキュメントでは意味がありません(そのroot-one
中にルート要素がなくtl:data
、唯一のルートです)。そのようなケースをすべて見つけて(/r1:root-one/
)、それらを(に変換したい)/tl:data/r1:root-one/
)したがって、式は新しいドキュメントのコンテキストで機能します。
正確なルールを指定するのは難しいです。/
パスの先頭に表示される(したがって、サブXMLドキュメントのドキュメントルートを参照する) " "は、それぞれ" /tl:data/
"に置き換える必要があります。これにより、新しく作成されたドキュメントのドキュメントルートが参照されるようになります。
Edit04
上記のテキストに示されているように、ソリューションは考えられるすべてのXPath式で機能するはずです。追加の例(r1名前空間からの架空の要素が構成されています-これは私の頭の中でより良く聞こえました):
<iso:assert test="r1:group=/r1:root-one/r1:item-classes/r1:item-class[r1:class=current()/r1:class]/r1:group and r1:imaginary-element1=/r1:root-one/r1:item-classes/r1:item-class[r1:class=current()/r1:class]/r1:imaginary-element1" />
<iso:assert test="r1:group=/r1:root-one/r1:item-classes/r1:item-class[r1:class=/r1:root-one/r1:imaginary-constants/r1:imaginary-constant]/r1:group" />
になる必要があります
<iso:assert test="r1:group=/tl:data/r1:root-one/r1:item-classes/r1:item-class[r1:class=current()/r1:class]/r1:group and r1:imaginary-element1=/tl:data/r1:root-one/r1:item-classes/r1:item-class[r1:class=current()/r1:class]/r1:imaginary-element1" />
<iso:assert test="r1:group=/tl:data/r1:root-one/r1:item-classes/r1:item-class[r1:class=/tl:data/r1:root-one/r1:imaginary-constants/r1:imaginary-constant]/r1:group" />
Edit05
XSLT2.0プロセッサに切り替えるオプションがあります。したがって、XSLT2.0ソリューションを受け入れます。
実際、誰かがXPath 1.0式内のドキュメントルートを表す符号と一致するXSLT正規表現を提供できれば、これで問題は解決します(関数を使用します)。私はXPath1.0の文法を調べてきましたが、まだ有用なものは何も付属していません。/
replace()