XML节点模板——我应该使用XSLT吗?

XML node template - should I use XSLT?

本文关键字:XSLT 我应该 节点 XML      更新时间:2023-10-16

我有一个具有以下结构(多个"实体"节点)的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库。


<

编辑:例子/strong>。

模板文件:

<!-- 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。不需要合并相同id的group节点。

如果你有一个文件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文件需要与样式表位于同一目录

除了进行任何类型的XML转换之外,还有一个选项是导入另一个XML文件,然后从标记中引用它。请看这里的例子。

这将要求您的用户为每种模板类型拥有单独的模板文件,这可能不是您想要的。然而,由于接吻原则,我更喜欢导入方法。如果您不熟悉XSLT,那么导入可能也是一种更好的方法。

我希望这对你有帮助!