1

これが私が持っているものです。

私のデータ: data.xml

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="myxslt2.xslt"?>
<data>
    <foo>
        <innerfoo1>inner-foo-1-text</innerfoo1>
        <innerfoo2>inner-foo-2-text</innerfoo2>
    </foo>
    <bar>Hello World</bar>
    <foobar>This is a test</foobar>
</data>

私のメタデータ - これは、どのデータ ノードを表示するかを xslt に伝えます。

メタデータ.xml

<Metadata>
    <Data>
        <Detail>foobar</Detail>
        <Detail>bar</Detail>
        <Detail>foo/innerfoo1</Detail>  
    </Data>

</Metadata>

innerfoo2 以外のすべてを表示します。

私の xslt: myxslt.xsl

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl" version="1.0">
    <xsl:output method="html" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" indent="yes"/>
    <xsl:variable name="main" select="/data"/>
    <xsl:template name="myTemplate">
        <xsl:param name="myparam"/>
        <xsl:param name="node"/>

        Node: <xsl:value-of select="$node"/><br/>
        Inner:<xsl:value-of select="msxsl:node-set($myparam)/data/*[local-name() = $node][1]"/>
    </xsl:template>
    <xsl:template match="/data">
        <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
        HTML STARTS
            <br/>
            <xsl:variable name="data" select="."/>
            Outer1:<xsl:value-of select="$data"/>
            <br/>
            Outer2:<xsl:value-of select="$data/foobar"/>
            <br/>
            <xsl:variable name="defaultMetadata" select="document('metadata.xml')"/>
            <xsl:for-each select="msxsl:node-set($defaultMetadata)/Metadata/Data/Detail">
                <br/>----<br/>
                <xsl:call-template name="myTemplate">
                    <xsl:with-param name="node">
                        <xsl:value-of select="."></xsl:value-of>
                    </xsl:with-param>

                    <xsl:with-param name="myparam">
                        <xsl:copy-of select="$data"/>
                    </xsl:with-param>
                </xsl:call-template>

            </xsl:for-each>
        </html>
    </xsl:template>
</xsl:stylesheet>

(読みやすくするためのペーストビン - http://pastebin.com/Uw7bFYWM )

出力:

HTML STARTS 
Outer1: inner-foo-1-text inner-foo-2-text Hello World This is a test 
Outer2:This is a test

----
Node: foobar
Inner:This is a test
----
Node: bar
Inner:Hello World
----
Node: foo/innerfoo1
Inner: 

だから私がやっていることは、メタデータの各詳細要素をループし、表示するノードの名前であるデータを渡すテンプレートを呼び出すことです。

次に、テンプレートはそのノードを解決して表示します。

ここでは、単一レベルの要素をうまく解決していることがわかりますが、local-name() = $node複数の要素の深さがある場合、その比較は使用できません。

私がやりたいことは次のようなものです:

Inner:<xsl:value-of select="msxsl:node-set($myparam)/data/$node"/>

しかし、これはうまくいきません。

どうすればこれを達成できますか?

4

3 に答える 3

1

質問のコメントの提案に従って、単純な式を動的に評価する再帰関数を次に示します。

<xsl:template name="recursiveTemplate">
    <xsl:param name="data"/>
    <xsl:param name="node"/>

    <xsl:for-each select="msxsl:node-set($data)/*/*">
        <xsl:choose>

            <xsl:when test="contains($node,'/')">
                <!--not the final node so recursion required-->
                <xsl:if test="substring-before($node, '/') = local-name() ">
                    <xsl:call-template name="recursiveTemplate">
                        <xsl:with-param name="data">
                            <xsl:copy-of select="."/>
                        </xsl:with-param>
                        <xsl:with-param name="node">
                            <xsl:value-of select="substring-after($node,'/')"/>
                        </xsl:with-param>
                    </xsl:call-template>
                </xsl:if>
            </xsl:when>

            <xsl:otherwise>
                <!--final node, so find the one that matches -->
                <xsl:if test="local-name()= $node">
                    <xsl:value-of select="."/>
                </xsl:if>
            </xsl:otherwise>

        </xsl:choose>

    </xsl:for-each>

</xsl:template>

と呼ばれる

    <xsl:call-template name="recursiveTemplate">
        <xsl:with-param name="data">
            <xsl:copy-of select="msxsl:node-set($myparam)/data"/>
        </xsl:with-param>
        <xsl:with-param name="node">
            <xsl:value-of select="$node"/>
        </xsl:with-param>
    </xsl:call-template>

これは信じられないほど冗長で複雑に思えますが、うまくいきます。これを他の方法で実装する方法について何か提案はありますか?

于 2013-10-21T22:21:37.343 に答える
1

XSLT 1.0 に行き詰まっていて、動的評価を使用する拡張関数を使用できない場合は、特定の制限があれば、純粋な XSLT でこれを行うことができます。この特定の回答の制限は、metadata.xmlの xpath 式は、条件のないノードのリストではないということです。

この特定の回答を示す前に、現在の XSLT であっても、ここではノード セット拡張関数を使用する必要がないことに注意してください。「結果ツリーのフラグメント」を XSLT で照合できるノードに変換する場合は、node-set を使用します。入力ドキュメントを直接参照している場合は、実際には必要ありません。あなたがそれが必要だと思うかもしれない理由は、実際にはこの行のためです...

 <xsl:with-param name="myparam">
     <xsl:copy-of select="$data"/>
 </xsl:with-param>

あなたはこれを行う必要があります..

<xsl:with-param name="myparam" select="$data"/>

xsl:copy-ofを使用するということは、実際には結果ツリー フラグメントを作成していることを意味しますが、後者の呼び出しはコピーを作成するのではなく、元のノードを参照しています。

とにかく、これを解決するには、myTemplateを再帰的なテンプレートにすることができます。現在のパラメーターにスラッシュが含まれているかどうかを確認するという考えです。その場合、スラッシュの前に要素の名前を持つノードを見つけ、新しいパラメーターとしてmyTemplateを再帰的に呼び出し、スラッシュの後に残りのexpressinも渡します。

<xsl:template name="myTemplate">
    <xsl:param name="myparam"/>
    <xsl:param name="node"/>

<xsl:choose>
    <xsl:when test="contains($node, '/')">
                <xsl:call-template name="myTemplate">
                     <xsl:with-param name="node" select="substring-after($node, '/')" />
                     <xsl:with-param name="myparam" select="$myparam/*[local-name() = substring-before($node, '/')][1]"/>
                </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
            Node: <xsl:value-of select="$node"/><br/>
            Inner:<xsl:value-of select="$myparam/*[local-name() = $node][1]"/>
    </xsl:otherwise>
</xsl:choose>
</xsl:template>

したがって、出力は、スラッシュのない式を取得した場合にのみ生成されます。

このXSLTを試してください

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="html" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" 

indent="yes"/>
    <xsl:variable name="main" select="/data"/>
    <xsl:template name="myTemplate">
        <xsl:param name="myparam"/>
        <xsl:param name="node"/>

    <xsl:choose>
        <xsl:when test="contains($node, '/')">
                    <xsl:call-template name="myTemplate">
                         <xsl:with-param name="node" select="substring-after($node, '/')" />
                         <xsl:with-param name="myparam" select="$myparam/*[local-name() = substring-before($node, '/')][1]"/>
                    </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
                Node: <xsl:value-of select="$node"/><br/>
                Inner:<xsl:value-of select="$myparam/*[local-name() = $node][1]"/>
        </xsl:otherwise>
    </xsl:choose>
    </xsl:template>

    <xsl:template match="/data">
        <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
        HTML STARTS
            <br/>
            <xsl:variable name="data" select="."/>
            Outer1:<xsl:value-of select="$data"/>
            <br/>
            Outer2:<xsl:value-of select="$data/foobar"/>
            <br/>
            <xsl:variable name="defaultMetadata" select="document('metadata.xml')"/>
            <xsl:for-each select="$defaultMetadata/Metadata/Data/Detail">
                <br/>----<br/>
                <xsl:call-template name="myTemplate">
                    <xsl:with-param name="node" select="." />
                    <xsl:with-param name="myparam" select="$data"/>
                </xsl:call-template>
            </xsl:for-each>
        </html>
    </xsl:template>
</xsl:stylesheet>
于 2013-10-21T22:27:06.220 に答える
-1

交換するだけ

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl" version="1.0">

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:msxsl="urn:schemas-microsoft-com:xslt"
  xmlns:ext="http://exslt.org/common"
  exclude-result-prefixes="ext msxsl" version="1.0">

そしてそれmsxsl:node-setext:node-set機能させるために。

完全な xslt は次のとおりです。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:ext="http://exslt.org/common"
  exclude-result-prefixes="ext msxsl" version="1.0">

  <xsl:output method="html" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
    doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" indent="yes"/>
  <xsl:variable name="main" select="/data"/>
  <xsl:template name="myTemplate">
    <xsl:param name="myparam"/>
    <xsl:param name="node"/> Node: <xsl:value-of select="$node"/><br/> Inner:<xsl:choose>
      <xsl:when test="contains($node,'foo/')"><xsl:value-of
          select="ext:node-set($myparam)/data/foo/*[local-name() = substring-after($node,'/')][1]"
        /></xsl:when>
      <xsl:otherwise><xsl:value-of select="ext:node-set($myparam)/data/*[local-name() = $node][1]"
        /></xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template match="/data">
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> HTML STARTS <br/>
      <xsl:variable name="data" select="."/> Outer1:<xsl:value-of select="$data"/>
      <br/> Outer2:<xsl:value-of select="$data/foobar"/>
      <br/>
      <xsl:variable name="defaultMetadata"
        select="document('metadata.xml')"/>
      <xsl:for-each select="ext:node-set($defaultMetadata)/Metadata/Data/Detail">
        <br/>----<br/>
        <xsl:call-template name="myTemplate">
          <xsl:with-param name="node"><xsl:value-of select="."/></xsl:with-param>
          <xsl:with-param name="myparam"><xsl:copy-of select="$data"/></xsl:with-param>
        </xsl:call-template>
      </xsl:for-each>
    </html>
  </xsl:template>
</xsl:stylesheet>
于 2013-10-21T12:31:43.507 に答える