このXSLT1.0変換:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:param name="pWanted" select="//img"/>
<xsl:param name="pWantedAttr" select="'url'"/>
<xsl:template match="/">
<xsl:apply-templates select="$pWanted"/>
</xsl:template>
<xsl:template match="*[not(starts-with(@xml:base, '/'))]">
<xsl:apply-templates select="ancestor::*[@xml:base][1]"/>
<xsl:value-of select="concat(@xml:base,@*[name()=$pWantedAttr])"/>
<xsl:if test="not(@xml:base)"><xsl:text>
</xsl:text></xsl:if>
</xsl:template>
<xsl:template match="*[starts-with(@xml:base, '/')]">
<xsl:value-of select="@xml:base"/>
</xsl:template>
</xsl:stylesheet>
このXMLドキュメントに適用した場合:
<t>
<a xml:base="/news/" >
<b xml:base="reports/">
<c xml:base="politics/" />
<c xml:base="/sports/" >
<d xml:base="reports/" />
<d xml:base="photos/" >
<img url="A1.jpg" />
<img url="A2.jpg" />
</d>
</c>
<c xml:base="entertainment" />
</b>
</a>
</t>
必要な正しい結果を生成します。
/sports/photos/A1.jpg
/sports/photos/A2.jpg
更新-単一のXPath2.0式ソリューション:
for $target in //img,
$top in $target/ancestor::*[starts-with(@xml:base,'/')][1]
return
string-join(
(
$top/@xml:base
, $top/descendant::*
[@xml:base and . intersect $target/ancestor::*]
/@xml:base
, $target/@url,
'
'
),
''
)
XSLT 2.0ベースの検証:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:sequence select=
"for $target in //img,
$top in $target/ancestor::*[starts-with(@xml:base,'/')][1]
return
string-join(
(
$top/@xml:base
, $top/descendant::*
[@xml:base and . intersect $target/ancestor::*]
/@xml:base
, $target/@url,
'
'
),
''
)
"/>
</xsl:template>
</xsl:stylesheet>
この変換が提供されたXMLドキュメントに適用される場合:
<t>
<a xml:base="/news/" >
<b xml:base="reports/">
<c xml:base="politics/" />
<c xml:base="sports/" >
<d xml:base="reports/" />
<d xml:base="photos/" >
<img url="A1.jpg" />
<img url="A2.jpg" />
</d>
</c>
<c xml:base="entertainment" />
</b>
</a>
</t>
XPath式が評価され、この評価の結果が出力にコピーされます。
/news/reports/sports/photos/A1.jpg
/news/reports/sports/photos/A2.jpg
変更されたドキュメントの場合:
<t>
<a xml:base="/news/" >
<b xml:base="reports/">
<c xml:base="politics/" />
<c xml:base="/sports/" >
<d xml:base="reports/" />
<d xml:base="photos/" >
<img url="A1.jpg" />
<img url="A2.jpg" />
</d>
</c>
<c xml:base="entertainment" />
</b>
</a>
</t>
ここでも、必要な正しい結果が生成されます。
/sports/photos/A1.jpg
/sports/photos/A2.jpg
Update2:
OPは、この単純化を提案しています。
元の投稿者によって追加された更新:完全なURLが相対URLに置き換わった完全なアプリケーションに埋め込まれると、Dimitreのアプローチはこの単純なものになりました
:
<xsl:template match="@url">
<xsl:attribute name="url">
<xsl:apply-templates mode="uri" select=".." />
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
<xsl:template match="*" mode="uri">
<xsl:if test="not(starts-with(@xml:base, '/'))">
<xsl:apply-templates select="ancestor::*[@xml:base][1]" mode="uri"/>
</xsl:if>
<xsl:value-of select="@xml:base"/>
</xsl:template>