1

繰り返しになりますが、今回は本当の問題があります... XML が 1 つあり、別の XML のフィルターを使用して別の XML に変換する必要があります。

File_in.xml:

    <?xml version="1.0" encoding="ISO-8859-15"?>
    <root>
        <item>
            <server>001023541</server>
            <name>P1</name>
            <desc>Production</desc>
            <status>1</status>
            <ram>1024</ram>
            <hdd>8 To</hdd>
        </item>
        <item>
            <server>201012345</server>
            <name>P2</name>
            <desc>Production</desc>
            <status>4</status>
            <ram>2048</ram>
            <hdd>8 To</hdd>
        </item>
        <item>
            <server>120332416</server>
            <name>P1</name>
            <desc>Production</desc>
            <status>2</status>
            <ram>8196</ram>
            <hdd>8 To</hdd>
        </item>
    </root>

そして別の XML:

フィルタ.xml

    <?xml version="1.0" encoding="ISO-8859-15"?>
    <Filtre>
        <Bloc5>
            <Part1>
                <EAN>001023541</EAN>
                <EAN>012356549</EAN>
                <EAN>012356559</EAN>
                <EAN>012356569</EAN>
            </Part1>
            <Part2>
                <EAN>201012345</EAN>
                <EAN>201012346</EAN>
                <EAN>201012347</EAN>
            </Part2>
        </Bloc5>
    </Filtre>

/root/item/server が /Filtre/Bloc5/Part1/EAN の要素と一致する場合、置き換えます

        <item>
            <server>001023541</server>
            <name>P1</name>
            <desc>Production</desc>
            <status>1</status>
            <ram>1024</ram>
            <hdd>8 To</hdd>
        </item>

        <item>
            <server>MAIN</server>
            <status>PRODUCTION</status>
        </item>

それ以外の場合、/root/item/server が /Filtre/Bloc5/Part2/EAN の要素と一致する場合は、置き換えます

        <item>
            <server>201012345</server>
            <name>P2</name>
            <desc>Production</desc>
            <status>4</status>
            <ram>2048</ram>
            <hdd>8 To</hdd>
        </item>

        <item>
            <server>BACKUP</server>
            <status>STOPPED</status>
        </item>

もう一方は次のように自動的に置き換えられます。

        <item>
            <server>120332416</server>
            <name>P1</name>
            <desc>Production</desc>
            <status>2</status>
            <ram>8196</ram>
            <hdd>8 To</hdd>
        </item>

        <item>
            <name>OFFLINE</name>
            <desc>Production</desc>
        </item>

次の方法で、(フィルタリングに使用される) XML の名前を取得します。

            <!-- filter settings -->
            <xsl:param name="filter_xml" />
            <xsl:variable name="filter" select="document('$filter_xml')" />

そして私のコードがあります:

        <xsl:for-each select="root/item">
            <xsl:choose>
                <xsl:when test="index-of(($filter/Filtre/Bloc5/Part1/EAN), ./server)">
                <item>
                    <server>MAIN</server>
                    <status>PRODUCTION</status>
                </item>
                </xsl:when>
            <xsl:when test="index-of(($filter/Filtre/Bloc5/Part2/EAN), ./server)" >
                <item>
                    <server>BACKUP</server>
                    <status>STOPPED</status>
                </item>
            </xsl:when >
            <xsl:otherwise>
                <item>
                    <name>OFFLINE</name>
                    <desc>Production</desc>
                </item>
            </xsl:otherwise>
        </xsl:for-each>

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

4

2 に答える 2

2

はるかにクリーンでシンプルかつ効率的な解決策は、複雑な分岐の代わりにテンプレート マッチングを使用することです。質問に XSLT バージョン番号のタグを付けていないため、XSLT 2.0 を想定していますが、XSLT 1.0 が必要な場合は、簡単に調整できます。

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

<xsl:variable name="filter" select="document('filter.xml')/*" />

<xsl:template match="/" >
 <root>
   <xsl:apply-templates select="*/item" />
 </root>
</xsl:template>

<xsl:template match="item[server=$filter/Bloc5/Part1/EAN]" >
  <item>
    <server>MAIN</server>
    <status>PRODUCTION</status>
  </item>
</xsl:template>

<xsl:template match="item[server=$filter/Bloc5/Part2/EAN]" >
  <item>
    <server>BACKUP</server>
    <status>STOPPED</status>
  </item>
</xsl:template>

<xsl:template match="item" >
  <item>
    <name>OFFLINE</name>
    <desc>Production</desc>
  </item>
</xsl:template>

</xsl:stylesheet>

更新: ケーキのアイシング

ご了承いただきありがとうございます。おまけとして、最初の 2 つのアイテムテンプレートを、この 1 つのより一般的で拡張可能なテンプレートに置き換えることもできます。しかし、それがより単純か、より複雑かは議論の余地があります。

代替の汎用アイテム テンプレート (XSLT 2.0 でのみ機能) ...

<xsl:template match="item[server=$filter/Bloc5/*/EAN]" >
  <xsl:variable name="part-no"
    select="substring-after(local-name(($filter/Bloc5/*[EAN=current()/server])[1]),
            'Part') cast as xs:integer" />
  <xsl:copy>
    <server><xsl:value-of select="('MAIN'      ,'BACKUP' )[$part-no]" /></server>
    <status><xsl:value-of select="('PRODUCTION','STOPPED')[$part-no]" /></status>
  </xsl:copy>
</xsl:template>
于 2012-09-03T13:13:41.543 に答える
1

調整する必要がある2つのこと:

  1. のパスdocument()は、フィルター変数の値である必要があります。現在、文字列「$filter」を渡しています。<xsl:variable name="filter" select="document('$filter_xml')" /> に変更する必要があります <xsl:variable name="filter" select="document($filter_xml)" />

  2. このcontains()関数は、各パラメーターの文字列入力を想定しています。contains()各フィルタの に対してテストを評価するには、要素EANの述語フィルタ内でテストを実行します。EANたとえば、次を に変更<xsl:when test="index-of(($filter/Filtre/Bloc5/Part1/EAN), ./server)"><xsl:when test="$filter/Filtre/Bloc5/Part1/EAN[contains(., ./server)]">ます。何かが一致する場合、結果は少なくとも 1EACになり、テストで評価さtrue()れます。

XSLT の例に適用:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
    <xsl:output indent="yes"/>
    <xsl:param name="filter_xml" />
    <xsl:variable name="filter" select="document($filter_xml)" />

    <xsl:template match="/">

        <xsl:for-each select="root/item">
            <xsl:choose>
                <xsl:when test="$filter/Filtre/Bloc5/Part1/EAN[contains(., ./server)]">
                    <item>
                        <server>MAIN</server>
                        <status>PRODUCTION</status>
                    </item>
                </xsl:when>
                <xsl:when test="$filter/Filtre/Bloc5/Part2/EAN[contains(., ./server)]" >
                    <item>
                        <server>BACKUP</server>
                        <status>STOPPED</status>
                    </item>
                </xsl:when >
                <xsl:otherwise>
                    <item>
                        <name>OFFLINE</name>
                        <desc>Production</desc>
                    </item>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>
于 2012-09-03T12:35:13.970 に答える