过滤,合并和排序XML节点列表

时间:2016-01-18 14:09:05

标签: sorting xslt xpath merge xslt-2.0

我正按照http://www.ibm.com/developerworks/library/x-tipcombxslt/的说明合并我的XML文件。但是,我想一次完成更多任务,无法找到办法。基本上,我想过滤合并的输入(已经工作)并对输出进行排序(需要帮助)。

source.xml 定义要合并的包含节点(在我的情况下编码标准违规)的文件。但是,其中一些违反了比我想要保留在输出中的规则更多的规则,所以我指定<rule>来保持在<ruleset>范围内。如果未列出任何规则,则应保留所有规则。

<rulesets>
  <ruleset file="ruleset_M1.xml"/>
  <ruleset file="ruleset_all2.xml">
    <rule>X</rule>
    <rule>Y</rule>
  </ruleset>
</rulesets>

所以我希望ruleset_M1.xml中的所有规则以及X中的Yruleset_all2.xml规则。

ruleset_all2.xml 如下所示:

<violations>
  <violation file="Bra.h" line="1" rule="Z"
             msg="Function SPARC_Convert is not documented."/>
  <violation file="CpuArch.h" line="120" rule="X"
             msg="Parameters of member GetBe32 are not documented."/>
  <violation file="CpuArch.h" line="87" rule="X"
             msg="Parameters of member GetUi32 are not documented."/>
  <violation file="heapmgr.h" line="56" rule="Y"
             msg="The following parameter of HeapManager() is not documented: fill"/>
</violations>

ruleset_M1.xml 包含更多违反更多规则的行为, all 应保留这些规则。

我设法使用以下XSLT进行过滤和合并。

<xsl:stylesheet version="2.0">
  <xsl:template match="/rulesets">
    <violations>
      <xsl:apply-templates>
        <xsl:sort select="@file"/><!-- help needed -->
      </xsl:apply-templates>
    </violations>
  </xsl:template>

  <xsl:template match="ruleset">
    <xsl:choose>
      <xsl:when test="rule != ''">
        <xsl:variable name="current-rules" select="rule"/>
        <xsl:copy-of select="document(@file)/violations/violation[@rule = $current-rules]"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:copy-of select="document(@file)/violations/violation"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

现在我想按文件名(violation/@file)对输出进行排序,但我的<xsl:sort>不起作用。 XPath @file<ruleset>的属性匹配,而不是<violation>。我试图用document(@file)/violations/violation/@file和其他一些选项替换它但没有成功。我可以以某种方式在第二个模板的输出节点中选择一个属性而不是当前源吗?或者我应该彻底改变我的XSL?

1 个答案:

答案 0 :(得分:1)

如果合并有效,我认为最简单的方法是首先合并,然后通过更改

进行排序
  <xsl:template match="/rulesets">
    <violations>
      <xsl:apply-templates>
        <xsl:sort select="@file"/><!-- help needed -->
      </xsl:apply-templates>
    </violations>
  </xsl:template>

  <xsl:template match="/rulesets">
    <violations>
      <xsl:variable name="merged">
        <xsl:apply-templates select="ruleset"/>
      </xsl:variable>
      <xsl:perform-sort select="$merged/violation">
        <xsl:sort select="@file"/>
      </xsl:perform-sort>
    </violations>
  </xsl:template>

每当我看到与xsl匹配时:选择,如

  <xsl:template match="ruleset">
    <xsl:choose>
      <xsl:when test="rule != ''">
        <xsl:variable name="current-rules" select="rule"/>
        <xsl:copy-of select="document(@file)/violations/violation[@rule = $current-rules]"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:copy-of select="document(@file)/violations/violation"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

我认为它应该重组为

<xsl:template match="ruleset[rule]">
  <xsl:copy-of select="document(@file)/violations/violation[@rule = current()/rule]"/>
</xsl:template>

<xsl:template match="ruleset[not(rule)]">
  <xsl:copy-of select="document(@file)/violations/violation"/>
</xsl:template>

作为替代方案,我认为你可以使用

  <xsl:template match="/rulesets">
    <violations>
      <xsl:perform-sort select="for $rs in ruleset[rule] return document($rs/@file)/violations/violation[@rule = $rs/rule], for $rs2 in ruleset[not(rule)] return document($rs2/@file)/violations/violation">
        <xsl:sort select="@file"/>
      </xsl:apply-templates>
    </violations>
  </xsl:template>

而不是

  <xsl:template match="/rulesets">
    <violations>
      <xsl:apply-templates>
        <xsl:sort select="@file"/><!-- help needed -->
      </xsl:apply-templates>
    </violations>