XML Module での XPath の使用 - Mule 4

<xml-module:xpath-extract>​ 操作は、XPath 式の評価をサポートしています。

XPath 式は各要素の任意の数値に一致する可能性があるため、この操作によって文字列のリストが返されます。要素が式に一致しない場合、この操作によって空のリストが返されます。

XPath 式も名前空間に対応しているため、この操作では名前空間のマッピングを使用できます。これらのマッピングは、参照される ​namespace-directory​ で定義される ​namespaces​ とマージされます。つまり、評価では両方の名前空間のマッピングのセットが組み合わされます。

MuleSoft は XPath 標準をサポートしていますが、DataWeave でも同じユースケースを実現でき、XML ドキュメントを抽出して変換するツールとして DataWeave をお勧めします。

次の例は、ウィリアム・シェイクスピアの戯曲『オセロ』の脚本を記載した XML を処理する方法を示しています。XML ファイルは次のようになります。

全文が上記の形式のテキストがあるとします。次のスクリプトを使用して、「​handkerchief​」という単語が含まれるすべての行を抽出できます。

XPath スクリプト
<xml-module:xpath-extract xpath="//LINE[contains(., $word)]"> (1)
    <xml-module:context-properties>#[{'word': 'handkerchief'}]</xml-module:context-properties> (2)
</xml-module:xpath-extract>
xml
1 $​ プレフィックスを使用してコンテキストプロパティを参照する XPath 式を提供します。
2 context-properties​ パラメーターで DataWeave を使用してコンテキストプロパティを生成します。

上記の XPath スクリプトにより、次の文字列のリストが出力されます。各 ​LINE​ はリストの異なる項目です。

出力
<LINE>For the same handkerchief?</LINE>
<LINE>What handkerchief?</LINE>
<LINE>What handkerchief?</LINE>
<LINE>Have you not sometimes seen a handkerchief</LINE>
<LINE>I know not that; but such a handkerchief--</LINE>
<LINE>Where should I lose that handkerchief, Emilia?</LINE>
<LINE>Lend me thy handkerchief.</LINE>
<LINE>That handkerchief</LINE>
<LINE>Fetch me the handkerchief: my mind misgives.</LINE>
<LINE>The handkerchief!</LINE>
<LINE>The handkerchief!</LINE>
<LINE>The handkerchief!</LINE>
<LINE>Sure, there's some wonder in this handkerchief:</LINE>
<LINE>But if I give my wife a handkerchief,--</LINE>
<LINE>But, for the handkerchief,--</LINE>
<LINE>Boding to all--he had my handkerchief.</LINE>
<LINE>--Handkerchief--confessions--handkerchief!--To</LINE>
<LINE>--Is't possible?--Confess--handkerchief!--O devil!--</LINE>
<LINE>mean by that same handkerchief you gave me even now?</LINE>
<LINE>By heaven, that should be my handkerchief!</LINE>
<LINE>And did you see the handkerchief?</LINE>
<LINE>That handkerchief which I so loved and gave thee</LINE>
<LINE>By heaven, I saw my handkerchief in's hand.</LINE>
<LINE>I saw the handkerchief.</LINE>
<LINE>It was a handkerchief, an antique token</LINE>
<LINE>O thou dull Moor! that handkerchief thou speak'st of</LINE>
<LINE>How came you, Cassio, by that handkerchief</LINE>
xml

デフォルトでは、この操作はメッセージペイロードレベルで XML ドキュメントを変換しようとします。ただし、​content​ パラメーターを使用して入力ドキュメントを提供できます。

<flow name="linesFromOthello">
    <file:read path="othello.xml" target="othello" />
    <xml-module:xpath-extract xpath="//LINE[contains(., $word)]">
        <xml-module:content>#[vars.othello]</xml-module:content>
        <xml-module:context-properties>#[{'word': 'handkerchief'}]</xml-module:context-properties>
    </xml-module:xpath-extract>
</flow>
xml

上記の例では、他の場所 (この場合、ファイルシステムのファイル) からコンテンツを取得し、シンプルな式を使用して参照しています。

名前空間のマッピング

入力 XML ドキュメントに名前空間が異なる要素が含まれている場合があります。次に例を示します。

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body foo="bar">
    <ns1:echo xmlns:mule="http://simple.component.mule.org/">
      <ns1:echo>Hello!</ns1:echo>
    </ns1:echo>
  </soap:Body>
</soap:Envelope>
xml

次の例では、XPath 式で使用される各 ​prefix​ を対応する名前空間 ​uri​ にマップします。

 <flow name="xpathWithInlineNs">
    <xml-module:xpath-extract xpath="/soap:Envelope/soap:Body/mule:echo/mule:echo">
        <xml-module:namespaces>
            <xml-module:namespace prefix="soap" uri="http://schemas.xmlsoap.org/soap/envelope/"/>
            <xml-module:namespace prefix="mule" uri="http://simple.component.mule.org/"/>
        </xml-module:namespaces>
    </xml-module:xpath-extract>
</flow>
xml

しかし、同じ名前空間を使用する複数の XPath 式を実行する必要がある場合にはどうでしょうか? 毎回マッピングを実行せずに済むように、マッピングに ​namespace-directory​ を作成し、そのディレクトリを参照することができます。次に例を示します。

<xml-module:namespace-directory name="fullNs"> (1)
    <xml-module:namespaces>
        <xml-module:namespace prefix="soap" uri="http://schemas.xmlsoap.org/soap/envelope/"/>
        <xml-module:namespace prefix="mule" uri="http://simple.component.mule.org/"/>
    </xml-module:namespaces>
</xml-module:namespace-directory>

<flow name="xpathWithFullNs">
    <xml-module:xpath-extract
      xpath="/soap:Envelope/soap:Body/mule:echo/mule:echo"
      namespaceDirectory="fullNs"/> (2)(3)
</flow>
xml
1 namespace-directory​ 要素を使用して、プレフィックスを実際の名前空間の URI にマップします。これらのプレフィックスは入力ドキュメントのプレフィックスに一致する必要があります。
2 続いて、これらのプレフィックスを XPath 式で参照できます。
3 最後に、​namespaceDirectory​ パラメーターを使用してステップ 1 で作成されたマッピングを参照します。

最後に、ユースケースを組み合わせることができます。たとえば、マッピングが含まれるグローバルな ​namespaceDirectory​ を用意して、操作レベルでマッピングを追加することができます。この組み合わせは、ドキュメントが多数あり、そのすべてに ​soap​ 名前空間が含まれているが 1 つのドキュメントにしか ​mule​ 名前空間が含まれていない場合に便利です。

<xml-module:namespace-directory name="partialNs"> (1)
    <xml-module:namespaces>
        <xml-module:namespace prefix="soap" uri="http://schemas.xmlsoap.org/soap/envelope/"/>
    </xml-module:namespaces>
</xml-module:namespace-directory>

<flow name="xpathWithMergedNs">
    <xml-module:xpath-extract
      xpath="/soap:Envelope/soap:Body/mule:echo/mule:echo"
      namespaceDirectory="partialNs"> (2) (3)
        <xml-module:namespaces>
            <xml-module:namespace prefix="mule" uri="http://simple.component.mule.org/"/> (4)
        </xml-module:namespaces>
    </xml-module:xpath-extract>
</flow>
xml
1 以前と同じように ​namespace-directory​ を宣言しますが、共通の名前空間のみを指定します。
2 XPath 式を提供します。
3 部分的な名前空間ディレクトリを参照します。
4 追加のマッピングを提供します。

マッピングと XPath 式で使用されるプレフィックスが入力ドキュメントで使用されるプレフィックスに一致することが重要です。

関数としての XPath の使用

XML Module は、XPath を使用して値を抽出するための DataWeave 関数を提供します。これは、​<choice>​ ルーターや ​<foreach>​ ルーターなどの場合に便利です。

この関数は任意の DataWeave 変換内でも使用できます。

<foreach> での XPath 関数の使用

次の例では、​<foreach>​ を使用して前の​オセロの行​の例のすべての行を反復処理し、それらを個別に処理します。

<foreach collection="#[XmlModule::xpath('//LINE', payload, {})]">
    <flow-ref name="processLine" />
</foreach>
xml
  • 最初の引数は XPath 式です。

  • 2 つ目の引数は入力ドキュメントで、この場合、メッセージペイロードです。

  • 3 つ目の引数はコンテキストプロパティです。この場合は必要ではないため、関数は空のオブジェクトを渡します (​{}​)。

  • 4 つ目の引数は​省略可能​であり、式の xpath を評価する名前空間を指定しています。

<choice> での XPath 関数の使用

オセロの行​の例に戻り、入力ドキュメントに単語 ​handkerchief​ が含まれない場合に何かを実行するとします。

<choice>
    <when expression="#[isEmpty(XmlModule::xpath('//LINE[contains(., \$word)]', vars.untrustedOthello, {'word': 'handkerchief'}))]">
        <flow-ref name="alteredOthello" />
    </when>
</choice>
xml
  • XmlModule::xpath​ 関数はリストを返すため、前の例では DataWeave ​isEmpty()​ 関数を使用して出力が空かどうかをテストします。

  • XPath 関数の最初に引数は、​$word​ コンテキストプロパティを使用する式です。

  • 2 つ目の引数は変数内の入力ドキュメントです。

  • 3 つ目の引数はコンテキストプロパティ値を提供します。

  • 4 つ目の引数は​省略可能​であり、式の xpath を評価する名前空間を指定しています。

名前空間での XPath 関数の使用

入力ドキュメントに XML 名前空間が含まれている場合、評価を実行するために XPath 関数にその情報が必要です。 次の例では、​set-payload​ コンポーネントを使用して書籍のタイトル、執筆者の名前、書籍の year タグを入力ドキュメントから取得します。このドキュメントには、明示的なデフォルトの ​xmlns​ 属性と、言語と執筆者に関するその他の ​xmlns​ 属性があります。

<?xml version="1.0" encoding="UTF-8"?>
<Book xmlns="http://www.books.org/2001/XMLSchema"
      xmlns:lang="http://www.books.org/2001/XMLLang"
      xmlns:author="http://www.books.org/2001/XMLAuthors">
    <Title>Fundamentals</Title>
    <Year>2001</Year>
    <author:name>David Mills</author:name>
    <lang:name>English</lang:name>
</Book>
xml

最初の例では、書籍のタイトルを取得するために ​set-payload​ コンポーネントを次のように設定します。

<set-payload value="#[XmlModule::xpath('/b:Book/b:Title/text()', payload, {}, [{prefix:'b', uri:'http://www.books.org/2001/XMLSchema'}])]" />
xml

結果の出力は ​Fundamentals​ です。

2 つ目の例では、執筆者の名前を取得するために ​set-payload​ コンポーネントを次のように設定します。

<set-payload value="#[XmlModule::xpath('/b:Book/author:name/text()', payload, {}, [{prefix:'b', uri:'http://www.books.org/2001/XMLSchema'}, {prefix:'author', uri:'http://www.books.org/2001/XMLAuthors'}])]" />
xml

結果の出力は ​David Mills​ です。

3 つ目の例では、書籍の year タグを取得するために ​set-payload​ コンポーネントを次のように設定します。

<set-payload value="#[XmlModule::xpath('/b:Book/b:Year', payload, {}, [{prefix:'b', uri:'http://www.books.org/2001/XMLSchema'}])]" />
xml

xmlns​ 属性が含まれる結果の出力は ​<Year xmlns="http://www.books.org/2001/XMLSchema">2001</Year>​ です。

関連情報