1

このソース ドキュメントを考えると:

<?xml version="1.0" encoding="utf-8"?>
<config>
  <group name="global">
    <globals>
      <item grp="db" prop="userid" value="foo"/>
      <item grp="db" prop="passwd" value="bar"/>
      <item grp="log" prop="level" value="debug"/>
      <item grp="log" prop="filename" value="red.log"/>
    </globals>
  </group>
  <group name="dev">
    <globals>
      <item grp="db" prop="server" value="dev_sql_1"/>
    </globals>
    <locals>
      <item grp="db" prop="catalog" value="red_db_local"/>
      <item grp="db" prop="passwd" value="dev_passwd"/>
      <item grp="log" prop="level" value="info"/>
    </locals>
  </group>
  <group name="qa">
    <globals>
      <item grp="db" prop="server" value="qa_sql_1"/>
      <item grp="db" prop="catalog" value="qa_db"/>  <!-- this is wonky, but may happen -->
    </globals>
    <locals>
      <item grp="db" prop="catalog" value="red_db_local"/> <!-- this should beat 'qa_db' from ../globals/item[@grp='db' and prop='catalog'] -->
      <item grp="db" prop="passwd" value="qa_passwd"/>
      <item grp="log" prop="level" value="critical"/>
    </locals>
  </group>
  <group name="prod">
    <globals>
      <item grp="db" prop="server" value="prod_sql_1"/>
    </globals>
    <locals>
      <item grp="db" prop="catalog" value="prod_db_local"/>
      <item grp="db" prop="passwd" value="prod_passwd"/>
      <item grp="log" prop="level" value="critical"/>
    </locals>
  </group>
</config>

および利用可能な環境の 1 つであるパラメーター、マージされて重複排除されたノードセットになり、最も具体的な値を保持したいと思います。したがって、「製品」の場合:

<config>
  <item grp="db" prop="userid" value="foo"/>
  <item grp="log" prop="filename" value="red.log"/>
  <item grp="db" prop="server" value="prod_sql_1"/>
  <item grp="db" prop="catalog" value="prod_db_local"/>
  <item grp="db" prop="passwd" value="prod_passwd"/>
  <item grp="log" prop="level" value="critical"/>
</config>

私は XSLT 1.0 でキーを使用するのが初めてで、'prod' では機能するが、'dev' や 'qa' では機能しないこのスタイルシートを思いつきました。

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
    version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
  <xsl:param name="environment"/>

  <!-- 
    using | to create a union of top-level global items and and env-specific items
  -->
  <xsl:variable name="all-items"
                select="/config/group[@name='global']/globals/item |
                        //group[@name=$environment]//item"/>

  <xsl:key name="dupes" match="item" use="concat(@grp,'|',@prop)"/>

  <xsl:template match="/config">
    <xsl:copy>
      <xsl:copy-of
          select="$all-items[generate-id() = generate-id(key('dupes',
                    concat(@grp,'|',@prop))[last()])]"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

これは私が目指しているアプローチです:

  1. <item.../>関連するすべてのノードを結合してノードセットにマージします|
  2. このノード セットを@grpおよび@prop属性でグループ化します
  3. 結果のグループのいずれかで最後のノードを保持します (重複除外)

私はキーに慣れていないので、このコードのビットを考えているとしか言えません。

<xsl:copy-of select="$all-items[generate-id() = generate-id(key('dupes',
                                            concat(@grp,'|',@prop))[last()])]"/>

last()重複アイテムのノードセットからノードを選択していますが、「dev」または「qa」で実行すると、次のようになります。

REG zacharyyoung$ xsltproc --stringparam environment dev config3.xsl config3.xml 
<config>
  <item grp="db" prop="userid" value="foo"/>
  <item grp="log" prop="filename" value="red.log"/>
</config>
REG zacharyyoung$ xsltproc --stringparam environment qa config3.xsl config3.xml
<config>
  <item grp="db" prop="userid" value="foo"/>
  <item grp="log" prop="filename" value="red.log"/>
</config>

各環境パラメーターの中間変数all-itemsを確認しましたが、少なくともそれだけは正しく機能しているようです。

<group name="qa"/>下に移動すると、次のようになります。

<config>
  <group name="global">...</group>
  <group name="dev">...</group>
  <group name="prod">...</group>
  <group name="qa">...</group>
<config>

次に、「qa」で実行すると動作します:

REG zacharyyoung$ xsltproc --stringparam environment qa config3.xsl config3.xml
<config>
  <item grp="db" prop="userid" value="foo"/>
  <item grp="log" prop="filename" value="red.log"/>
  <item grp="db" prop="server" value="qa_sql_1"/>
  <item grp="db" prop="catalog" value="red_db_local"/>
  <item grp="db" prop="passwd" value="qa_passwd"/>
  <item grp="log" prop="level" value="critical"/>
</config>

では、なぜ<group name="...">...</group>I'm selection の位置が重要なのでしょうか? 具体的には、最後の位置でしか機能しないのはなぜですか?また、どの位置でも機能させるにはどうすればよいですか?

編集1

$all-items(任意の環境で)データを分離して独自のファイルに入れると、XSL は正しく機能します。次の例は、グローバルと「dev」の結合です。

<config>
  <item grp="db" prop="userid" value="foo"/>
  <item grp="db" prop="passwd" value="bar"/>
  <item grp="log" prop="level" value="debug"/>
  <item grp="log" prop="filename" value="red.log"/>
  <item grp="db" prop="server" value="dev_sql_1"/>
  <item grp="db" prop="catalog" value="red_db_local"/>
  <item grp="db" prop="passwd" value="dev_passwd"/>
  <item grp="log" prop="level" value="info"/>
</config>

そしてこのXSL:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
  <xsl:key name="dupes" match="item" use="concat(@grp,'|',@prop)"/>
  <xsl:template match="/config">
    <xsl:copy>
          <xsl:copy-of
              select="item[generate-id() = generate-id(key('dupes',
                      concat(@grp,'|',@prop))[last()])]"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

結果:

REG zacharyyoung$ xsltproc config4.xsl config4.xml
<config>
  <item grp="db" prop="userid" value="foo"/>
  <item grp="log" prop="filename" value="red.log"/>
  <item grp="db" prop="server" value="dev_sql_1"/>
  <item grp="db" prop="catalog" value="red_db_local"/>
  <item grp="db" prop="passwd" value="dev_passwd"/>
  <item grp="log" prop="level" value="info"/>
</config>

それで、今は変数に落ちているように見えますall-itemsか?

ありがとうございました。

4

2 に答える 2

0

DevNull の回答(記載されている質問に回答します) から外れて、次の変更を行いました (記載されていない要件について) 。

  1. 重複する値が入力された場合に備えて、ミックスする環境グローバルを追加しました
  2. 私のニーズに合わないと思われるため、恒等変換を削除しました

完全なスタイルシートは次のとおりです。

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

  <xsl:param name="environment" select="'qa'"/>

  <xsl:template match="/config">
    <xsl:copy>
      <xsl:copy-of select="/config/group[@name='global']/globals/item[not(@prop = /config/group[@name=$environment]//item/@prop)]"/>
      <xsl:copy-of select="/config/group[@name=$environment]/globals/item[not(@prop = /config/group[@name=$environment]/locals/item/@prop)]"/>
      <xsl:copy-of select="/config/group[@name=$environment]/locals/item"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

元の質問のキーの何が問題なのかを知りたいと思っています。

于 2012-01-16T22:45:44.077 に答える