【问题标题】:XSLT Removing duplicatesXSLT 删除重复项
【发布时间】:2016-02-16 01:42:06
【问题描述】:

我有一个如下所示的 xml 数据源:

<dsQueryResponse>
  <Department>
    <Rows>
      <Row dept="HR" state="NY" region="East"/>
      <Row dept="HR" state="NJ" region="East"/>
      <Row dept="SD" state="NY" region="East"/>
      <Row dept="MM" state="NY" region="East"/>
      <Row dept="SD" state="NJ" region="East"/>
      <Row dept="SD" state="CO" region="West"/>
      <Row dept="MM" state="CO" region="West"/>
    </Rows>
  </Department>
</dsQueryResponse>

我的 XSLT 如下所示:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
  <xsl:output method="html" indent="no"/>
  <xsl:decimal-format NaN=""/>
  <xsl:param name="DeptQS">East</xsl:param>
  <xsl:variable name="deptRows" select="/dsQueryResponse/Department/Rows/Row[@region = $DeptQS]"/>

  <xsl:template match="/">
    <xsl:if test="count($deptRows) &gt; 0">
      <xsl:call-template name="deptList"/>
    </xsl:if>
  </xsl:template>

  <xsl:template name="deptList">
    <xsl:for-each select="$deptRows">
      <!-- process unique depts--> 
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

我想把该地区的所有部门都写出来。我现在拥有的代码将写出重复的部门。但是我怎样才能只写一次该地区的部门呢?

谢谢!

【问题讨论】:

  • 请提供实际和预期的结果。否则很难理解你到底需要什么。

标签: xml xslt


【解决方案1】:

你没有显示你想要的输出。但在 XSLT 2.0 中,您可以这样做:

<xsl:template match="Rows">
  <xsl:for-each-group select="Row" group-by="@region">
    <region name="{current-grouping-key()}">
      <xsl:for-each-group select="current-group()" group-by="@dept">
        <dept name="{current-grouping-key()}">
          <xsl:for-each select="current-group()">
            <state name="{@state}"/>
          </xsl:for-each>
        </dept>
      </xsl:for-each-group>
    </region>
  </xsl:for-each>
</xsl:template>

【讨论】:

  • 感谢您编辑,西蒙。我使用&lt;/ 来结束带有自动完成功能的 XML 编辑器中的标签,因此在这样的注释中编写“粗略”的 XML 时,我倾向于将其用作速记;这是向读者发出的一个信号,他们应该对其应用一些脑循环,而不是仅仅粘贴代码并期望它开箱即用。
【解决方案2】:

对于 XSLT 1.0,您可以使用“Muenchian Method”。

您将创建一个键来通过@region@dept 值的组合来索引Row 元素。

然后您将获得该区域/部门组合的第一次出现(具有所需区域 ($DeptQS))并输出部门 (dept)。

这是一个输出 &lt;test&gt; 元素以显示上下文的示例样式表:

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

  <xsl:key name="kDept" match="Department/Rows/Row" use="concat(@region,'|',@dept)"/>
  <xsl:param name="DeptQS">East</xsl:param>

  <xsl:template match="/*">
    <xsl:for-each select="Department/Rows/Row[count(.|key('kDept',
      concat($DeptQS,'|',@dept))[1])=1]">
      <test>Current dept: <xsl:value-of select="@dept"/></test>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

这是使用输入 XML 的输出:

<test>Current dept: HR</test>
<test>Current dept: SD</test>
<test>Current dept: MM</test>

【讨论】:

  • 变量/参数引用在 XSLT 1.0 模式中无效xsl:key/@match
  • 您不能在 XSLT 1.0 模式中使用 var/param 引用,但您可以在 XSLT 2.0 中使用。这改变了整个问题,因为在 XSLT 1.0 中您必须使用推送样式。您的答案在模式中使用拉式样式和参数参考。 这不是您的第一句话似乎声称的 XSLT 1.0 解决方案。
【解决方案3】:

我怎样才能写出部门 该地区只有一次?

这个样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:param name="pRegion" select="'East'"/>
    <xsl:key name="kRowByDept-Region" match="Row"
             use="concat(@dept,'++',@region)"/>
    <xsl:template match="Rows">
        <xsl:apply-templates select="Row[generate-id()
                                          = generate-id(
                                               key('kRowByDept-Region',
                                                   concat(@dept,'++',$pRegion)
                                               )[1]
                                            )
                                     ]"/>
    </xsl:template>
    <xsl:template match="Row">
        <xsl:value-of select="concat(@dept,'&#xA;')"/>
    </xsl:template>
</xsl:stylesheet>

输出:

HR
SD
MM

【讨论】:

    【解决方案4】:

    以下样式表显示了在多个级别进行分组的一般方法:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:key name="byRegion" match="Row" use="@region" />
        <xsl:key name="byRegionState" 
                 match="Row" use="concat(@region, '|', @state)" />
        <xsl:key name="byRegionStateDept" 
                 match="Row" use="concat(@region, '|', @state, '|', @dept)" />
        <xsl:template 
             match="Row[generate-id() = generate-id(key('byRegion', @region)[1])]">
            <region name="{@region}">
                <xsl:apply-templates
                    select="key('byRegion', @region)
                             [generate-id() =
                              generate-id(key('byRegionState',
                                          concat(@region, '|', @state))[1])]"
                    mode="states" />
            </region>
        </xsl:template>
        <xsl:template match="Row" mode="states">
            <state name="{@state}">
                <xsl:apply-templates
                    select="key('byRegionState', concat(@region, '|', @state))
                             [generate-id() =
                              generate-id(key('byRegionStateDept',
                                    concat(@region, '|', @state, '|', @dept))[1])]"
                    mode="dept" />
            </state>
        </xsl:template>
        <xsl:template match="Row" mode="dept">
            <dept><xsl:value-of select="@dept" /></dept>
        </xsl:template>
    </xsl:stylesheet>
    

    它会在您的输入中产生以下输出:

    <region name="East">
        <state name="NY">
            <dept>HR</dept>
            <dept>SD</dept>
            <dept>MM</dept>
        </state>
        <state name="NJ">
            <dept>HR</dept>
            <dept>SD</dept>
        </state>
    </region>
    <region name="West">
        <state name="CO">
            <dept>SD</dept>
            <dept>MM</dept>
        </state>
    </region>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-08-03
      • 1970-01-01
      • 2011-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多