このソリューションでは、XPATH 入力情報を少し再編成し、2 段階の変換を許可する必要があります。最初の変換でスタイルシートが作成され、2 番目の変換で実行されます。したがって、クライアントは XSLT エンジンを 2 回呼び出す必要があります。問題がある場合はお知らせください。
第一歩
このように、XPATH 情報を XML ドキュメントに再編成してください。難しいことではなく、XSLT スクリプトでさえもこの作業を行うように記述できます。
<paths>
<rule>
<match>article[1]/id[1]</match>
<namespaces>
<namespace prefix="ns1">http://predic8.com/wsdl/material/ArticleService/1/</namespace>
<!-- The namespace node declares a namespace that is used in the match expression.
There can be many of these. It is not required to define the s11: namespace,
nor the ns1 namespace. -->
</namespaces>
<replacement>1</replacement>
</rule>
<rule>
<match>article[1]/description[1]</match>
<namespaces/>
<replacement>bar</replacement>
</rule>
... etc ...
</paths>
解の制約
上記の規則文書では、次のように制約されています。
- 一致には暗黙的に接頭辞「expression: /create/」が付きます。それを明示的に入れないでください。
- すべての一致は article[n] のように開始する必要があります。n は序数です。
- ルールをゼロにすることはできません。
- s11="http://schemas.xmlsoap.org/soap/envelope/" および ns1="http://predic8.com/wsdl/material/ArticleService/1/" 以外の、一致で使用するプレフィックス. (注:名前空間が「/」で終わるのは有効ではないと思いますが、それについてはわかりません)、名前空間ノードで定義されています。
上記は、ステップ 1 の変換への入力ドキュメントです。このドキュメントをこのスタイルシートに適用...
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:step2="http://www.w3.org/1999/XSL/Transform-step2"
xmlns:s11="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="http://predic8.com/wsdl/material/ArticleService/1/"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes='xsl'>
<xsl:output method="xml" indent="yes" encoding="UTF-8" />
<xsl:namespace-alias stylesheet-prefix="step2" result-prefix="xsl"/>
<xsl:template match="/">
<step2:stylesheet version="2.0">
<step2:output method="xml" indent="yes" encoding="UTF-8" />
<step2:variable name="replicated-template" as="element()*">
<step2:apply-templates select="/" mode="replication" />
</step2:variable>
<step2:template match="@*|node()" mode="replication">
<step2:copy>
<step2:apply-templates select="@*|node()" mode="replication" />
</step2:copy>
</step2:template>
<step2:template match="/s11:Envelope/s11:Body/ns1:create/article" mode="replication">
<step2:variable name="replicant" select="." />
<step2:for-each select="for $i in 1 to
{max(for $m in /paths/rule/match return
xs:integer(substring-before(substring-after($m,'article['),']')))}
return $i">
<step2:for-each select="$replicant">
<step2:copy>
<step2:apply-templates select="@*|node()" mode="replication" />
</step2:copy>
</step2:for-each>
</step2:for-each>
</step2:template>
<step2:template match="@*|node()">
<step2:copy>
<step2:apply-templates select="@*|node()"/>
</step2:copy>
</step2:template>
<step2:template match="/">
<step2:apply-templates select="$replicated-template" />
</step2:template>
<xsl:apply-templates select="paths/rule" />
</step2:stylesheet>
</xsl:template>
<xsl:template match="rule">
<step2:template match="s11:Envelope/s11:Body/ns1:create/{match}">
<xsl:for-each select="namespaces/namespace">
<xsl:namespace name="{@prefix}" select="." />
</xsl:for-each>
<step2:copy>
<step2:apply-templates select="@*"/>
<step2:value-of select="'{replacement}'"/>
<step2:apply-templates select="*"/>
</step2:copy>
</step2:template>
</xsl:template>
</xsl:stylesheet>
ステップ2
ステップ 1 で出力されたスタイルシートに、入力ドキュメントとして SOAP エンベロープ ファイルを適用します。その結果、必要に応じて変更された元の SOAP ドキュメントが作成されます。これは、ステップ 2 のスタイルシートのサンプルです。説明を簡単にするために、最初のルール (/create/article[1]/id => 1) のみを考慮しています。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:s11="http://schemas.xmlsoap.org/soap/envelope/"
version="2.0">
<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template xmlns:ns1="http://predic8.com/wsdl/material/ArticleService/1/"
match="/s11:Envelope/s11:Body/ns1:create[1]/article[1]/id[1]">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:value-of select="'1'"/>
<xsl:apply-templates select="*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
その他の解の制約
- テンプレート ドキュメントには、少なくとも 1 つの /s11:Envelope/s11:Body/ns1:create/article が含まれている必要があります。ルールの要求に従って、アーティクル ノードのみが (深く) レプリケートされます。それ以外はどんな構造でも構いません。
- テンプレート ドキュメントには、s11:Envelope/s11:Body/ns1:create ノードのネストされたレベルを含めることはできません。
説明
XPATH 式がテンプレートの一致条件からそれほど離れていないことに気付くでしょう。したがって、XPATH と置換値をテンプレート ルールとして再表現するスタイルシートを作成することはそれほど難しくありません。スタイルシートを書くときに、 xsl:namespace-alias を使用すると、「xsl:」を命令として、「xsl:」を意図した出力として明確にすることができます。XSLT 3.0 が登場すると、このアルゴリズムを 1 つのステップに削減できる可能性が高くなります。動的な XPATH 評価が可能になるためです。これが実際の問題の核心です。しかし、当面は 2 段階のプロセスに満足する必要があります。
2 番目のスタイルシートは、2 フェーズの変換です。最初の段階では、ルールで必要な回数だけ、記事レベルからテンプレートを複製します。2 番目のフェーズでは、この複製されたテンプレートを解析し、XPATH によって示されるテキスト値を置換する動的ルールを適用します。
アップデート
私の元の投稿は間違っていました。エラーを指摘してくれた Dimitre に感謝します。上記の更新されたソリューションを見つけてください。
結果論
2 段階のソリューションでは複雑すぎて、wintel プラットフォームで実行している場合は、Saxon の商用バージョンの購入を検討してください。商用版には動的な XPATH 評価機能があると思います。私は商用版を持っていないので、そのような解決策を提供することはできません. evaluate() 関数を使用したソリューションの方がずっと簡単だと思います。XSLT は私にとって単なる趣味です。しかし、ビジネス目的で XSLT を使用している場合、価格は手頃な価格です。