0

次の構造の XML ファイルがあります (複数の「エンティティ」ノード)。

<!-- entities.xml -->
<root>
    <entity template="foo-template" kind="foo" name="bar">
        <groups>
            <group id="1">
                <definition id="1" name="foobar" />
            </group>
        </groups>
    </entity>
</root>

多くのentityノードには、同様の属性と子ノードがあります。entityユーザーが別のファイルにテンプレートを作成できるようにしたいと思います。テンプレートの参照は次のように行われます。

<entity template="foo-template" kind="foo" ... />

「foo-template」のすべての属性と子ノードはentity、既存のものを除いて、 にコピーする必要があります (つまり、テンプレートのオーバーライドを許可します)。

私は XSLT にあまり詳しくありません。それはこのタスクに適したツールですか、それともそれなしでこれを実装したほうがよいでしょうか?

私は C++ と RapidXml を使用していますが、他の XML ライブラリも使用できます。


編集: 例.

テンプレート ファイル:

<!-- templates.xml -->
<templates>
    <entity template="foo-template" name="n/a" model="baz">
        <groups>
            <group id="1">
                <definition id="1" name="def1" />
                <definition id="2" name="def2" />
            </group>
            <group id="2">
                <definition id="1" name="def3" />
                <definition id="2" name="def4" />
            </group>
        </groups>
    </entity>
</templates>

出力ファイル:

<!-- output.xml -->
<root>
    <entity kind="foo" name="bar" model="baz">
        <groups>
            <group id="1">
                <definition id="1" name="foobar" />
            </group>
            <group id="2">
                <definition id="1" name="def3" />
                <definition id="2" name="def4" />
            </group>
        </groups>
    </entity>
</root>

したがって、出力には「entities.xml」のグループ 1 と「templates.xml」のグループ 2 が含まれます。group同じ ID を持つノードをマージする必要はありません。

4

2 に答える 2

2

templates.xml次のようなファイルがある場合

<templates>
  <entity template="foo-template" kind="foo" name="bar" model="baz" />
  <!-- and other entity elements with different template="..." values -->
</templates>

次に、次のようなXSLTは、あなたが求めているものを達成します

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

  <xsl:key name="kEntityTemplate" match="entity" use="@template" />

  <!-- identity template - copy everything not overridden by another template -->
  <xsl:template match="@*|node">
    <xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy>
  </xsl:template>

  <xsl:template match="entity[@template]">
    <xsl:variable name="thisEntity" select="." />
    <!-- switch to templates doc -->
    <xsl:for-each select="document('templates.xml')">
      <xsl:variable name="template"
         select="key('kEntityTemplate', $thisEntity/@template)" />

      <entity>
        <!-- copy template attributes that are not overridden -->
        <xsl:for-each select="$template/@*">
          <xsl:if test="not($thisEntity/@*[name() = name(current())])">
            <!-- if not, copy the one from the template -->
            <xsl:apply-templates select="." />
          </xsl:if>
        </xsl:for-each>

        <!-- copy source attributes -->
        <xsl:apply-templates select="$thisEntity/@*[name() != 'template']" />

        <!-- deal with elements -->
        <xsl:if test="$thisEntity/groups/group | $template/groups/group">
          <groups>
            <!-- here we select all group elements from the source plus
                 those group elements from the template that do not also exist
                 in the source, and sort the whole lot by id -->
            <xsl:apply-templates select="$thisEntity/groups/group
              | $template/groups/group[not(@id = $thisEntity/groups/group/@id)]">
              <xsl:sort select="@id" data-type="number" />
            </xsl:apply-templates>
          </groups>
        </xsl:if>
      </entity>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

このtemplates.xmlファイルは、スタイルシートと同じディレクトリにある必要があります。

于 2013-03-05T14:02:56.213 に答える
0

あらゆる種類のXML変換を行う以外に使用できるオプションの1つは、他のXMLファイルをインポートし、タグ内からそれを参照することです。例については、こちらをご覧ください。

これには、ユーザーがテンプレートタイプごとに個別のテンプレートファイルを用意する必要がありますが、これは望ましくない場合があります。ただし、キスの原則があるため、インポートアプローチを使用したいと思います。XSLTに慣れていない場合は、インポートすることもおそらくより良い方法です。

これがお役に立てば幸いです。

于 2013-03-05T13:46:53.533 に答える