【问题标题】:XSLT - Checking if the previous value of the field (Date and Grant) is same as the current value and addingXSLT - 检查字段(日期和授予)的先前值是否与当前值相同并添加
【发布时间】:2014-07-09 18:30:37
【问题描述】:

我的 XSLT 遇到了几个问题(粘贴在下面)。

如果 Grant_Date 和 Grant_Value 相同,我正在尝试添加 Grant_Value 字段(下面粘贴了 XML)

使用前面的兄弟函数,我可以修剪行,以便具有相同 Grant_Date 和 Grant_Type 的行仅显示一次,但与这些行对应的 Grant_Value 需要汇总在一起,我无法也就是说,问题是可以有很多行具有相同的Grant Date和Grant Value,因此需要将它们对应的Grant Value加在一起。

其次,

我需要计算显示的最终行数\记录数。当我使用 count 函数时,它给了我不正确的值(它也显示了不属于前一个兄弟测试条件的记录,可能是因为它适用于 XML)。还有其他一些问题,所以有没有办法可以在 for-each 循环中设置一个计数器来给我正确的值?计数器变量可以计算 for-each 循环的迭代次数,并且可能会有所帮助。

最后,

我需要在最后一条记录之后删除换行符,我已经使用了位置功能,但由于前面的兄弟功能,它再次无法正常工作。我再次认为,因为这适用于 XML 数据,所以如果我使用前面的兄弟条件,我不会得到正确的值,没有它,它可以正常工作。

XML 数据:

<?xml version='1.0' encoding='UTF-8'?>
<ne:NODE xmlns:ne="namespacene" >
    <ne:NODEEntry>

        <ne:RECORD>GRANT</ne:RECORD>

        <ne:Grants>
            <ne:GRANT_DATE>20140402</ne:GRANT_DATE>
            <ne:GRANT_TYPE>GRANT1</ne:GRANT_TYPE>
            <ne:GRANT_VALUE>20000</ne:GRANT_VALUE>
        </ne:Grants>

        <ne:Grants>
            <ne:GRANT_DATE>20140402</ne:GRANT_DATE>
            <ne:GRANT_TYPE>GRANT1</ne:GRANT_TYPE>

            <ne:GRANT_VALUE>20000</ne:GRANT_VALUE>
        </ne:Grants>

        <ne:Grants>
            <ne:GRANT_DATE>20140403</ne:GRANT_DATE>
            <ne:GRANT_TYPE>GRANT1</ne:GRANT_TYPE>

            <ne:GRANT_VALUE>25000</ne:GRANT_VALUE>
        </ne:Grants>

        <ne:Grants>
            <ne:GRANT_DATE>20140402</ne:GRANT_DATE>
            <ne:GRANT_TYPE>GRANT1</ne:GRANT_TYPE>

            <ne:GRANT_VALUE>20000</ne:GRANT_VALUE>
        </ne:Grants> 

    </ne:NODEEntry>

</ne:NODE>

XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    exclude-result-prefixes="xs"
    xmlns:ne="namespacene"
    version="2.0">
    <xsl:output indent='no'  omit-xml-declaration="yes" method="text"/>


     <xsl:template match="ne:NODE">      

                <xsl:for-each select="ne:NODEEntry">
                <xsl:variable name="Record" select="ne:RECORD"/>

               <xsl:for-each select="ne:Grants">

                   <xsl:if test ="not(preceding-sibling::ne:Grants[ne:GRANT_DATE/text() = current()/ne:GRANT_DATE/text()]) and not(preceding-sibling::ne:Grants[ne:GRANT_DATE/text() = current()/ne:GRANT_TYPE/text()])" >

                <xsl:value-of select="$Record"/>               
               <xsl:text>|</xsl:text>                              
                <xsl:value-of select="ne:GRANT_DATE"/>
                   <xsl:text>|</xsl:text>
                <xsl:value-of select="ne:GRANT_TYPE"/>
                   <xsl:text>|</xsl:text>      
                <xsl:value-of select="ne:GRANT_VALUE"/>
                           <xsl:if test="position()!=last()">                                                        
                          <xsl:value-of select="'&#xA;'"/>    
                           </xsl:if>
                   </xsl:if>    
            </xsl:for-each>
            <xsl:value-of select="count(ne:Grants)"/> 
                </xsl:for-each>     
    </xsl:template>
</xsl:stylesheet>

XSLT 预期输出:

GRANT|20140402|GRANT1|60000
GRANT|20140403|GRANT1|25000
2

2 是输出文件中的总行数。 最后一个字段(在前 2 行中)总结了具有相同 Grant_Date 和 Grant_Type 的所有 Grant_Value。在这种情况下,日期 20140402 和类型 GRANT1 在 XML 中出现三次,因此对应于它们的 Grant_Value 应该加在一起,即 20000 + 20000 + 20000 = 60000

运行上述文件的当前输出:

GRANT|20140402|GRANT1|20000
GRANT|20140403|GRANT1|25000
4

这里我们得到 4,因为这是 XML 中的实际行数(包括第一行的重复条目),但这不是我们需要的,我们希望 2 应​​该在那里。 而且,光标实际上应该在最后一条记录之后(在这种情况下为 25000),它不应该转到下一行。为了更好地解释它,在这种情况下,4 应该与最后一条记录 25000 相邻,而不是转到下一行。

有人可以帮帮我吗,我完全被他们困住了。提前非常感谢。

请不要介意格式不好,这是我第一次来这里,真的很期待。

【问题讨论】:

  • 我已更正了您的格式(您需要确保普通文本不以 4 个或更多空格开头)。如果您在这种情况下显示您期望的输出,这将有所帮助,因为这样更容易看出问题所在。谢谢!
  • 另外,如果您确实在使用 XSLT 2.0,您可能需要阅读 xsl:for-each-group 命令,因为它可能是您需要的。 xml.com/lpt/a/1314.
  • 谢谢蒂姆,我在问题中添加了预期的输出和当前的输出。我不确定在这种情况下 for-each-group 会有多大帮助!

标签: xml xslt


【解决方案1】:

您可以将此视为一个分组问题,因为您实际上是将具有相同 GRANT_DATEGRANT_TYPE 值的元素组合在一起。在 XSLT 2.0 中,您将在此处使用 xsl:for-each-group

<xsl:for-each-group select="ne:Grants" group-by="concat(ne:GRANT_DATE, '|', ne:GRANT_TYPE)">

在这个外观中,您将被定位在第一个不同的元素上(基于日期和类型),因此循环内部将与您当前的相同。主要区别在于如何获得组中所有记录的总数。这可以通过使用“sum”函数和“current-group()”(返回组中的所有节点)轻松完成。

<xsl:value-of select="sum(current-group()/ne:GRANT_VALUE)"/>

在获取总记录方面,还可以利用distinct-values函数。

<xsl:value-of select="count(distinct-values(ne:Grants/(concat(ne:GRANT_DATE, '|', ne:GRANT_TYPE))))" />

试试这个 XSLT

<xsl:stylesheet  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    exclude-result-prefixes="xs" xmlns:ne="namespacene" version="2.0">
   <xsl:output indent='no' omit-xml-declaration="yes" method="text"/>

   <xsl:template match="ne:NODE">      
      <xsl:for-each select="ne:NODEEntry">
         <xsl:variable name="Record" select="ne:RECORD"/>
         <xsl:for-each-group select="ne:Grants" group-by="concat(ne:GRANT_DATE, '|', ne:GRANT_TYPE)">
            <xsl:value-of select="$Record"/>               
            <xsl:text>|</xsl:text>                              
            <xsl:value-of select="ne:GRANT_DATE"/>
            <xsl:text>|</xsl:text>
             <xsl:value-of select="ne:GRANT_TYPE"/>
             <xsl:text>|</xsl:text>      
             <xsl:value-of select="sum(current-group()/ne:GRANT_VALUE)"/>
             <xsl:value-of select="'&#xA;'"/>    
         </xsl:for-each-group>
         <xsl:value-of select="count(distinct-values(ne:Grants/(concat(ne:GRANT_DATE, '|', ne:GRANT_TYPE))))" />
     </xsl:for-each>     
   </xsl:template>
</xsl:stylesheet>

这应该输出以下内容

GRANT|20140402|GRANT1|60000
GRANT|20140403|GRANT1|25000
2

编辑:如果您需要多个 NODEEntry 元素,那么 XSLT 的这种变体也可以考虑分组中的 RECORD

<xsl:stylesheet  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    exclude-result-prefixes="xs" xmlns:ne="namespacene" version="2.0">
   <xsl:output indent='no' omit-xml-declaration="yes" method="text"/>

   <xsl:template match="ne:NODE">      
      <xsl:for-each-group select="ne:NODEEntry/ne:Grants" group-by="concat(../ne:RECORD, '|', ne:GRANT_DATE, '|', ne:GRANT_TYPE)">
          <xsl:value-of select="../ne:RECORD"/>               
          <xsl:text>|</xsl:text>                              
          <xsl:value-of select="ne:GRANT_DATE"/>
          <xsl:text>|</xsl:text>
           <xsl:value-of select="ne:GRANT_TYPE"/>
           <xsl:text>|</xsl:text>      
           <xsl:value-of select="sum(current-group()/ne:GRANT_VALUE)"/>
           <xsl:value-of select="'&#xA;'"/> 
        </xsl:for-each-group>
        <xsl:value-of select="count(distinct-values(ne:NODEEntry/ne:Grants/(concat(../ne:RECORD, '|', ne:GRANT_DATE, '|', ne:GRANT_TYPE))))" />
   </xsl:template>
</xsl:stylesheet>

【讨论】:

  • 非常感谢 Tim,我不知道 for-each 组的功能!我想不同值计数应该可以工作(到目前为止,它不适用于我的实际文件,但会检查)。你能帮我算出第一部分吗(根据类似的授予日期和类型对价值求和)。在这种情况下,输出的第一行应该显示 60000 而不是 20000。
  • 抱歉,我忘记了总价值。我已经编辑了我的答案以显示这一点。使用“current-group()”上的“sum”函数很容易完成
  • 嗨,蒂姆,很抱歉我的回复延迟,谢谢,当前组功能运行良好。但是,我在使用计数功能时遇到了一些问题。在这种情况下它可以正常工作,但是如果我们有超过 1 条记录说 GRANT2 并且它们的 GRANT_DATE 和 GRANT_TYPE 具有相同的值,那么这些记录将不是计数的一部分,因此我们需要连接 Record 字段 - ne:RECORD还有日期和类型,但由于字段 ne:RECORD 与 GRANT_DATE AND GRANT_TYPE 处于不同的节点级别,
  • contd.. 我将 ne:RECORD 的值放在一个变量中并尝试使用 $variable-name 进行连接,但不知何故该值没有被选中,因此它没有被包含在计数中。其次,我正在尝试使用 position() 函数来删除输出文件中最后一条记录之后的空间,但这似乎不起作用(理想情况下,应在输出中的最后一条记录 25000 之后立即打印最后两条) .
  • 我在 XSLT 的答案中添加了一个细微的变化,以显示如何将 ne:RECORD 包含在分组中。我不确定“最后一条记录后的空格”的问题,因为我没有任何空格!但是,您可以随时检查“位置()!= last()”吗?
猜你喜欢
  • 1970-01-01
  • 2017-01-15
  • 1970-01-01
  • 2020-02-29
  • 2017-11-17
  • 2020-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多