3

xslt で何らかの条件に基づいて属性を作成するにはどうすればよいですか。

私の入力xmlにはタグがあります:

          <track external="http://mysite.com"  />
              or
           <track  local="/myfolder" />

この 'track 要素には、外部属性またはローカル属性のいずれかが表示されますが、これらのいずれも表示されないため、次のように変換する必要があります

       <a xhtml:href="@external value" xmlns="http://www.w3.org/1999/xhtml" /> 

'track' 要素またはに 'external' 属性が発生した場合

       <a xlink:href="@local value" xmlns="http://www.w3.org/1999/xlink" /> 

「track」要素に「local」属性が発生した場合

XSLT が試した:

     <a xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xlink="http://www.w3.org/1999/xlink">      

      <xsl:for-each select="child::*" >
        <xsl:choose>

          <xsl:when test="name()='track'">
             <xsl:if test="@local">
            <xsl:attribute name="xlink:href">

            <xsl:value-of select="@local" />
            </xsl:attribute>
            </xsl:if>
               <xsl:if test="@external">
            <xsl:attribute name="xhtml:href">

            <xsl:value-of select="@external" />
            </xsl:attribute>
            </xsl:if>
          </xsl:when>
        </xsl:choose>
      </xsl:for-each>

      </a>

しかし、条件に基づいて「a」要素の属性を作成すると、例外がスローされます。これは XSLT 1.0 では受け入れられません。XSLT 1.0 の条件に基づいて、'a' 要素に属性を表示させる方法はありますか?

4

3 に答える 3

3

この変換:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xhtml="http://www.w3.org/1999/xhtml"
 xmlns:xlink="http://www.w3.org/1999/xlink"
 xmlns:my="my:my" exclude-result-prefixes="my">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <my:mappings>
  <map from="external" to="xhtml"/>
  <map from="local" to="xlink"/>
 </my:mappings>

 <xsl:variable name="vMaps" select="document('')/*/my:mappings/*"/>
 <xsl:variable name="vNamespaces" select="document('')/*/namespace::*"/>

 <xsl:template match="/*">
   <t><xsl:apply-templates/></t>
 </xsl:template>

 <xsl:template match="track">
     <xsl:element name="a"
       namespace="{$vNamespaces[name()=$vMaps[@from=name(current()/@*)]/@to]}">
       <xsl:apply-templates select="node()|@*"/>
   </xsl:element>
 </xsl:template>

 <xsl:template match="@*">
  <xsl:attribute name="{$vMaps[@from=name(current())]/@to}:href"
    namespace="{$vNamespaces[name()=$vMaps[@from=name(current())]/@to]}">
    <xsl:value-of select="."/>
  </xsl:attribute>
 </xsl:template>
</xsl:stylesheet>

この XML ドキュメントに適用した場合:

<t>
    <track external="http://mysite.com"  />
    <track  local="/myfolder" />
</t>

必要な正しい結果が生成されます。

<t xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xlink="http://www.w3.org/1999/xlink">
   <a xmlns="http://www.w3.org/1999/xhtml" xhtml:href="http://mysite.com"/>
   <a xmlns="http://www.w3.org/1999/xlink" xlink:href="/myfolder"/>
</t>

注意事項このソリューションには、次のような独自の機能がいくつかあります。

  1. 条件付き命令が使用されていないため、コードが単純になり、エラーが発生しにくくなります。

  2. 純粋な「プッシュ」スタイルが使用されます。

  3. まさに望んでいた結果が得られます。

于 2012-07-03T13:33:54.660 に答える
1

XSLT 1.0 で属性を条件付きで追加することを妨げるものは何もありません。ちなみに、XSLT では for-each を避け、代わりにテンプレートを使用してください。trackノード専用のテンプレートを次に示します。

<xsl:template match='track'>

    <a xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xlink="http://www.w3.org/1999/xlink">
        <xsl:if test="@local">
            <xsl:attribute name="xlink:href">
                    <xsl:value-of select="@local" />
            </xsl:attribute>
        </xsl:if>
        <xsl:if test="@external">
            <xsl:attribute name="xhtml:href">
                <xsl:value-of select="@external" />
            </xsl:attribute>
        </xsl:if>
    </a>

</xsl:template>

ただし、Tim C が述べたように、より良いパターンは、さまざまなテンプレートを介してさまざまな種類の着信属性を処理することです。何よりも、条件付きブロックで行き詰まらないため、これはよりクリーンです。

<xsl:template match='track'>
    <a><xsl:apply-templates select='@*' /></a>
</xsl:template>

<xsl:template match='@local' xmlns:xlink="http://www.w3.org/1999/xlink">
    <xsl:attribute name="xlink:href">
            <xsl:value-of select="." />
    </xsl:attribute>
</xsl:template>

<xsl:template match='@external' xmlns:xhtml="http://www.w3.org/1999/xhtml">
    <xsl:attribute name="xhtml:href">
        <xsl:value-of select="." />
    </xsl:attribute>
</xsl:template>

この XMLPlaygroundで、両方のアプローチの動作を確認できます。

于 2012-07-03T12:41:26.923 に答える
1

関連する状況に一致させるには、おそらくテンプレート マッチングを利用する必要があります。まず、 xsl:for-eachを使用する代わりにxsl:apply-templates を使用します。

<xsl:apply-templates select="*" />

そして、ローカルまたは外部の属性があるかどうかに合わせて個別のテンプレートを用意します

<xsl:template match="track[@external]">
    <a xhtml:href="{@external}" />
</xsl:template>

<xsl:template match="track[@local]">
    <a xlink:href="{@local}" />
</xsl:template>

ここに完全な XSLT があります

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xlink="http://www.w3.org/">
    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="album">
        <p>
        <xsl:apply-templates select="*" />
        </p>
    </xsl:template>

    <xsl:template match="track[@external]">
        <a xhtml:href="{@external}" />
    </xsl:template>

    <xsl:template match="track[@local]">
        <a xlink:href="{@local}" />
    </xsl:template>
</xsl:stylesheet>

以下の XSLT に適用する場合

<album>
   <track external="http://mysite.com"/>
   <track local="/myfolder"/>
</album>

以下が出力されます

<p xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xlink="http://www.w3.org/">
   <a xhtml:href="http://mysite.com" />
   <a xlink:href="/myfolder" />
</p>
于 2012-07-03T12:44:14.177 に答える