在XSLT中编辑相同元素时避免模糊规则匹配?

时间:2014-05-16 13:49:52

标签: xml xslt xpath

如果不应从转换中删除元素,我想向元素添加属性。我认为我当前的XSL会满足这个要求,首先丢弃所有不在allowedArticles变量中的元素,然后将属性添加到剩下的元素中。

然而,这不起作用,我不确定如何正确地做到这一点。我想两者都做,如果没有在allowedArticles中,则丢弃整个元素,如果它应该在转换中,则添加一个属性。

有人能指出我正确的方向吗?

这是我的示例XSL:

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

  <!-- Fetch the array from an external file: allowedArticles.xml -->
  <xsl:variable
    name="allowedArticles"
    select="document('allowedArticles.xml')/allowedArticles/articleId" />

  <!-- Identity template, copies every element in source file -->
  <xsl:template match="node() | @*">
    <xsl:copy>
      <xsl:apply-templates select="node() | @*" />
    </xsl:copy>
  </xsl:template>

  <!-- Matches content items that are NOT in the allowedArticles array,
    and discards them by doing nothing-->
  <xsl:template match="escenic:escenic/escenic:content[not(@exported-dbid=$allowedArticles)]" />

  <!-- Removes section-ref elements from within content elements -->
  <xsl:template match="escenic:escenic/escenic:content/escenic:section-ref" />

  <!-- Add delete-relations attribute to all content elements -->
  <xsl:template match="escenic:escenic/escenic:content">
    <xsl:copy>
      <xsl:attribute name="delete-relations">
        <xsl:value-of select="'true'" />
      </xsl:attribute>
      <xsl:apply-templates select="node() | @*" />
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

2 个答案:

答案 0 :(得分:1)

我发现了一个问题。它可能不是唯一一个,因为我不知道您的源文件是什么样的。

您的第二个模板会删除您不想要的文章,但您的上一个模板似乎会再次处理所有这些文章。您可以通过添加谓词来解决此问题:

<xsl:template match="escenic:escenic/escenic:content[@exported-dbid=$allowedArticles]">
    <xsl:copy>
        <xsl:attribute name="delete-relations">
            <xsl:value-of select="'true'" />
        </xsl:attribute>
        <xsl:apply-templates select="node() | @*" />
    </xsl:copy>
</xsl:template> 

答案 1 :(得分:1)

考虑以下两个模板规则:

<xsl:template match="escenic:escenic/escenic:content
                    [not(@exported-dbid=$allowedArticles)]" />

<xsl:template match="escenic:escenic/escenic:content">

虽然您和我很明显第一条规则匹配第二条规则匹配的节点的子集,但根据XSLT规范,它们都具有相同的优先级。因此,如果您希望第一个优先考虑,请给出明确的优先级,例如

<xsl:template match="escenic:escenic/escenic:content
                    [not(@exported-dbid=$allowedArticles)]" priority="6"/>

<xsl:template match="escenic:escenic/escenic:content" priority="5">

或者我怀疑父元素限定符只是噪声,因此您可以将规则写为:

<xsl:template match="escenic:content
                    [not(@exported-dbid=$allowedArticles)]" />

<xsl:template match="escenic:content">

如果您这样做,系统会计算出正确反映选择性的默认优先级,因此您无需添加手动优先级。

当然,按照@helderadocha的建议使规则互相排斥是另一种可能性,但一般来说XSLT难以实现,因此理解和使用模板规则优先级非常重要。