子要素に基づく派生値に基づいて要素を並べ替えたいと思います。sum
派生値は、XPath ( 、など)を使用して計算することはできませんがconcat
、XSL ( xsl:choose
、など) では計算できxsl:if
ます。
EXSLT 関数拡張を使用したいのですが、利用できません。この環境は、XSLT 1.0、Xalan-C++ バージョン 1.10 であり、EXSLT 共通および拡張機能が設定されています。
編集xsl:sort
例を変更して、グループ化する必要がある派生値は、ステートメント内の単純なノード/xpath 関数では計算できないことを強調しました。
私の目標は、開始日の降順に並べ替えて、現在の薬を非アクティブな薬の前にリストすることです。薬が最新であるかどうかを判断するロジックは、薬がキャンセルされたか、有効期限が切れていないか、およびその他のビジネス ロジックによって異なります。
この XML を考えると:
<?xml version="1.0"?>
<medications>
<medication>
<name>med1</name>
<status>canceled</status>
<startTime>2012-02-01T00:00:00Z</startTime>
<endTime>2012-12-31T00:00:00Z</endTime>
<!-- other elements omitted -->
</medication>
<medication>
<name>med2</name>
<status />
<startTime>2012-01-01T00:00:00Z</startTime>
<endTime>2012-01-07T00:00:00Z</endTime>
<!-- other elements omitted -->
</medication>
<medication>
<name>med3</name>
<status />
<startTime>2012-01-01T00:00:00Z</startTime>
<!-- other element omitted -->
</medication>
</medications>
スタイルシートは、例のデータから省略された情報 (注文医師、薬局の場所など) と親ノードからのデータ (患者の住所、主治医など) を含む、並べ替えられた医薬品のリストを生成します。この例では、投薬ノードをトラバースできることを示す単純なソート済みリストを作成します。
<?xml version="1.0" encoding="utf-8"?>
<medications>
<medication isCurrent="1" name="med3" />
<medication isCurrent="0" name="med1" />
<medication isCurrent="0" name="med2" />
</medications>
私が思いついた最善の方法は、導出された値を EXSLT ノード セットに事前に計算し (並べ替えに必要な他の値と共に)、キーを使用して、generate-id によって薬物要素を検索することです。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="http://exslt.org/common"
exclude-result-prefixes="exsl">
<xsl:output encoding="utf-8" method="xml" indent="yes" />
<xsl:key name="medications-by-id" match="medication" use="generate-id()" />
<xsl:variable name="medication-sorter">
<xsl:for-each select="//medication">
<item id="{generate-id(.)}">
<xsl:attribute name="isCurrent">
<xsl:apply-templates mode="isCurrentMedication" select="." />
</xsl:attribute>
<xsl:attribute name="startTime">
<xsl:value-of select="startTime/text()" />
</xsl:attribute>
</item>
</xsl:for-each>
</xsl:variable>
<xsl:template match="medications">
<!-- hardcoded key lookup works -->
<hardcoded><xsl:value-of select="key('medications-by-id',generate-id(medication[2]))/name/text()"/></hardcoded>
<!-- but key lookup from the sort helper does not -->
<medications>
<xsl:for-each select="exsl:node-set($medication-sorter)/item">
<xsl:sort select="@isCurrent" order="descending" />
<xsl:sort select="@startTime" order="descending" />
<medication>
<xsl:attribute name="isCurrent">
<xsl:value-of select="@isCurrent" />
</xsl:attribute>
<xsl:attribute name="name">
<xsl:value-of select="key('medications-by-id',@id)/name/text()" />
</xsl:attribute>
</medication>
</xsl:for-each>
</medications>
</xsl:template>
<xsl:template mode="isCurrentMedication" match="medication">
<xsl:choose>
<xsl:when test="(status/text()='canceled') or (status/text()='discontinued') or (status/text()='inactive')">0</xsl:when>
<xsl:otherwise>
<!-- omitted date checking logic not relevent to this question, so just hardcoded -->
<xsl:choose>
<xsl:when test="name/text()='med2'">0</xsl:when>
<xsl:when test="name/text()='med3'">1</xsl:when>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
ただし、これは期待どおりに機能しませんでした。generate-id(medication[2]) でキーを検索すると、ノードは有効で名前が出力されますが、値がまったく同じように見えても、ノード セットから @id を使用して呼び出された場合は機能しません。
<?xml version="1.0" encoding="utf-8"?>
<medications>
<hardcoded>med2</hardcoded>
<medication isCurrent="1" name="" />
<medication isCurrent="0" name="" />
<medication isCurrent="0" name="" />
</medications>
これも Xalan for Java 2.7.1 でテストし、同じ結果を得ました。
copy-of
$medication-sorter ノードセットに the drug 要素を含めることでこれを回避できますが、親コンテキストが失われ、私のスタイルシートがそれを必要とする場合があります。
を使用して計算する必要がある値の並べ替え/グループ化にアプローチする別の方法はありxsl:template
ますか?