1

私は次のXMLを持っています

<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type='text/xsl' href='parser.xsl'?>
<NVS>
    <A>
        <F>007</F>
    </A>
    <A>-002</A>
    <B>--003</B>
    <C>
        <D>------005</D>
    </C>
    <E>-006</E>
</NVS>

そして、次のような各ノードのツリーを印刷したいと思います:

/NVS/A/
/NVS/A/F/
/NVS/A/
/NVS/B/
/NVS/C/
/NVS/C/D
/NVS/E/

XSL をいくつか試しましたが、正しい結果が得られません。最高の XSL は次のとおりです。

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" encoding="ISO-8859-1" doctype-public="-//W3C//DTD XHTML//EN" doctype-system="http://www.w3.org/TR/2001/REC-xhtml11-20010531" indent="yes"/>
    <xsl:template match="/*">
        <html>
            <body>
                <xsl:for-each select=".">/<xsl:value-of select="."/>
                    <br/>
                </xsl:for-each>
            </body>
        </html>
    </xsl:template>
</xsl:stylesheet>

また、次のような「for-each」も試しました。

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" encoding="ISO-8859-1" doctype-public="-//W3C//DTD XHTML//EN" doctype-system="http://www.w3.org/TR/2001/REC-xhtml11-20010531" indent="yes"/>
    <xsl:template match="/*/*">
        <xsl:for-each select=".">/<xsl:value-of select="."/>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

しかし、良くはありません。また、ノードの名前のみが必要なのに対し、値を印刷するだけです。

何か案が?

4

2 に答える 2

2

考えられる解決策の 1 つは、ツリーをたどり、適切な出力を追跡することです。たとえば、次の XSLT の場合:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output omit-xml-declaration="yes" indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="/*">
    <xsl:apply-templates mode="children">
      <xsl:with-param name="pName" select="name()"/>
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="*[*]" mode="children">
    <xsl:param name="pName"/>
    <xsl:variable name="vNewName" select="concat($pName, '/', name())"/>
    <xsl:value-of select="concat('/', $vNewName, '/&#10;')"/>
    <xsl:apply-templates mode="children">
      <xsl:with-param name="pName" select="$vNewName"/>
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="*[not(*)]" mode="children">
    <xsl:param name="pName"/>
    <xsl:value-of select="concat('/', $pName, '/', name(), '/&#10;')"/>
  </xsl:template>

</xsl:stylesheet>

...提供された XML に適用されます。

<NVS>
  <A>
    <F>007</F>
  </A>
  <A>-002</A>
  <B>--003</B>
  <C>
    <D>------005</D>
  </C>
  <E>-006</E>
</NVS>

...必要な結果が生成されます。

/NVS/A/
/NVS/A/F/
/NVS/A/
/NVS/B/
/NVS/C/
/NVS/C/D/
/NVS/E/

説明:

  • $pNameテンプレート #1 はルート ノードに一致し、その時点でルート ノードの名前を含むパラメーターを単独で渡しながら、すべての子ノードにテンプレートを適用するようにプロセッサに指示します。の使用に注意してくださいmode="children"。私はこれを使用して、より一般的な一致を伴う将来のテンプレートにこのルート ノードが含まれないようにします。
  • テンプレート #2 は、子を持つ (および を使用しているmode="children") すべてのノードに一致します。このようなノードが見つかると、プロセッサは、キャリー アロング$pNameパラメーター、スラッシュ、および現在の要素の名前を組み合わせたテキスト行を出力します。最後に、テンプレートはすべての子ノードにテンプレートを適用し、パラメーターを渡すことで、テンプレート #1 を模倣します。ただし、今回は、パラメーターには、このノードまで作成され、このノードを含む連結テキストが含まれます。
  • テンプレート #3 は、子を持たない (また、 を使用しているmode="children") すべてのノードに一致します。そのようなノードが見つかると、プロセッサはテンプレート #2 とかなり似た処理を行うテキスト行を出力します。
于 2013-07-23T15:44:12.850 に答える
1

別のオプションは、ancestor-or-self軸を使用してツリーを上に戻ることです。

XML 入力

<NVS>
    <A>
        <F>007</F>
    </A>
    <A>-002</A>
    <B>--003</B>
    <C>
        <D>------005</D>
    </C>
    <E>-006</E>
</NVS>

XSLT1.0

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="text()"/>

    <xsl:template match="*">
        <xsl:for-each select="ancestor-or-self::*">
            <xsl:value-of select="concat('/',local-name())"/>
        </xsl:for-each>
        <xsl:text>&#xA;</xsl:text>
        <xsl:apply-templates select="node()"/>
    </xsl:template>

</xsl:stylesheet>

出力

/NVS
/NVS/A
/NVS/A/F
/NVS/A
/NVS/B
/NVS/C
/NVS/C/D
/NVS/E

要素が特定のレベルで複数回存在する場合、述語に位置を追加することにより、正確なパスを与えるように簡単に変更することもできます。たとえば、Aの子である 2 つの要素があり/NVSます。

XSLT1.0

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="text()"/>

    <xsl:template match="*">
        <xsl:for-each select="ancestor-or-self::*">
            <xsl:value-of select="concat('/',local-name())"/>
            <xsl:if test="(preceding-sibling::*|following-sibling::*)[local-name()=local-name(current())]">
                <xsl:value-of select="concat('[',count(preceding-sibling::*[local-name()=local-name(current())])+1,']')"/>
            </xsl:if>
        </xsl:for-each>
        <xsl:text>&#xA;</xsl:text>
        <xsl:apply-templates select="node()"/>
    </xsl:template>

</xsl:stylesheet>

出力(上記と同じ入力を使用)

/NVS
/NVS/A[1]
/NVS/A[1]/F
/NVS/A[2]
/NVS/B
/NVS/C
/NVS/C/D
/NVS/E

また、ルート要素出力へのパスが必要ない場合は、次のテンプレートを追加するだけです:

<xsl:template match="/*">
    <xsl:apply-templates/>
</xsl:template>
于 2013-07-23T16:20:59.097 に答える