可以使用模板使用w / Muenchian分组而不是for-each吗?

时间:2017-04-05 17:17:00

标签: xml xslt xpath muenchian-grouping

据我了解,在不必要时使用for-each循环是不好的形式。有人可以告诉我如何将嵌套的for循环与此XSL中的分组转换为单独的模板吗?当XML是分层的时,这似乎很容易,但对于扁平XML,我还没有弄清楚XPATH表达式或其他语法来实现这一点。

示例XML数据:

<?xml version = "1.0"?> 
<?xml-stylesheet type = "text/xsl" href = "time_detail_employee_m.xsl"?> 
<Employees>
  <Employee>
    <COMPANY_ID>83207</COMPANY_ID>        
    <PRJ_PROJECT_ID>104</PRJ_PROJECT_ID>
    <PRJ_PROJECT_NAME>Portal</PRJ_PROJECT_NAME>
    <PERSON_ID>5881</PERSON_ID>
    <TM_FIRST_NAME>Dave</TM_FIRST_NAME>
    <TM_LAST_NAME>Morgan</TM_LAST_NAME>
    <SR_ID>3075</SR_ID>
    <SR_TITLE>Shoe Page</SR_TITLE>
    <TM_BEGIN_DT>2015-12-11T00:00:00</TM_BEGIN_DT>
    <TM_BEGIN_TIME>10:45:00</TM_BEGIN_TIME>
    <TM_END_TIME>16:30:00</TM_END_TIME>
    <TM_TIME_CD>REG</TM_TIME_CD>
    <TM_BILLABLE>F</TM_BILLABLE>        
    <TM_WEEK>50</TM_WEEK>
    <TM_CALCULATED_TIME>5.750000</TM_CALCULATED_TIME>        
  </Employee>
  <Employee>
    ...
  </Employee>
  ...
</Employees>

XSL样式表:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:key name="group-by-person" match="Employee" use="PERSON_ID" />    
   <xsl:key name="group-by-week" match="Employee" use="concat(PERSON_ID,'|',TM_WEEK)" /> 
   <xsl:key name="group-by-day" match="Employee" use="concat(PERSON_ID,'|',TM_WEEK,'|',TM_BEGIN_DT)" /> 

   <xsl:variable name="space"><xsl:text> </xsl:text></xsl:variable>

   <xsl:template match="/">
      <html><body>   
         <xsl:apply-templates />
      </body></html>
   </xsl:template>

   <xsl:template match="Employees">
      <xsl:for-each select="Employee[count(. | key('group-by-person', PERSON_ID)[1]) = 1]">
         <xsl:sort select="TM_LAST_NAME" />
         <p><xsl:value-of select="TM_FIRST_NAME" /><xsl:value-of select="$space"/><xsl:value-of select="TM_LAST_NAME" /></p><br />

               <!-- begin week grouping -->         
               <xsl:for-each select="key('group-by-person', PERSON_ID)[count(. | key('group-by-week', concat(PERSON_ID,'|',TM_WEEK))[1]) = 1]">
                  <xsl:sort select="TM_WEEK" data-type="number"/>
                  <p><xsl:value-of select="TM_WEEK" /></p><br/>

                      <!-- begin day grouping -->
                      <xsl:for-each select="key('group-by-week', concat(PERSON_ID,'|',TM_WEEK))[count(. | key('group-by-day', concat(PERSON_ID,'|',TM_WEEK,'|',TM_BEGIN_DT))[1]) = 1]">
                          <xsl:sort select="TM_BEGIN_DT" />
                          <xsl:value-of select="substring-before(TM_BEGIN_DT,'T')" />
                          <br/>
                          <xsl:for-each select="key('group-by-day', concat(PERSON_ID,'|',TM_WEEK,'|',TM_BEGIN_DT))">
                              <p><xsl:value-of select="TM_BEGIN_TIME" /><xsl:value-of select="$space"/><xsl:value-of select="TM_END_TIME" /></p><br/>
                          </xsl:for-each>
                          <br/><xsl:text>daily sum = </xsl:text>
                          <xsl:value-of select="sum(key('group-by-day', concat(PERSON_ID,'|',TM_WEEK,'|',TM_BEGIN_DT))/TM_CALCULATED_TIME)" />
                          <br/>
                      </xsl:for-each>
                   <!-- end day grouping -->
                   <br/><xsl:text>weekly sum = </xsl:text>
                   <xsl:value-of select="sum(key('group-by-week', concat(PERSON_ID,'|',TM_WEEK))/TM_CALCULATED_TIME)" />
                   <br/>
               </xsl:for-each>               
               <!-- end week grouping -->
          <br/><xsl:text>person_id sum = </xsl:text>
          <xsl:value-of select="sum(key('group-by-person', PERSON_ID)/TM_CALCULATED_TIME)" />
          <br/>  
      </xsl:for-each>
   </xsl:template>   
</xsl:stylesheet>

示例输出,大概为:

Name 1 (based on PERSON_ID)
    Week 1 (based on TM_WEEK)
        Monday (based on TM_BEGIN_DT)
            time1 - time2 (TM_BEGIN_TIME - TM_END_TIME)
            time3 - time4
        Tuesday
            time1 - time2
    Week 2
        Thursday
            time1 - time2
            time3 - time4
            time5 - time6
Name 2
    Week 1
        Wednesday
            time1 - time2
Name 3, etc.

1 个答案:

答案 0 :(得分:2)

这应该是一个简单的任务,因为无论您使用CREATE TABLE copy_table AS SELECT * FROM original_table; 还是import RPi.GPIO as GPIO import time import fdb con = fdb.connect(dsn='10.100.2.197/3050:/home/trainee2/Desktop/ice', user='sysdba', password='trainee') text_file = open("namen1.txt", "r") lines = text_file.read().split(',') namen = lines text_file.close() status = [0] * 12 indexSpatie = 0 pinnen = [18,23,24,25,20,21,17,27,6,13,19,26] controlepin = [1] * 12 GPIO.setmode(GPIO.BCM) for p in range(0,12): GPIO.setup(pinnen[p],GPIO.IN) print pinnen[p] cur = con.cursor() while True: for e in range(0,12): status[e] = GPIO.input(pinnen[e]) if (status[e] != controlepin[e]): n = e naam = str(namen[n]) indexSpatie = naam.index(' ') voornaam = naam[:indexSpatie] achternaam = naam[indexSpatie:] stat = str(status[n]) datum = time.strftime("%d/%m/%Y") print( voornaam + achternaam + " met pinnummer: " + str(pinnen[n]) + " heeft status van " + stat + " op vandaag: " + datum) cur.execute("insert into ICEDATA (PRENAME, NAME, DATUM) values(?,?,?)",(voornaam,achternaam,datum)) controlepin[e] = status[e] time.sleep(1) ,xpath表达式都是相同的。唯一要考虑的是,至少在您的示例中,您最终可能会得到多个匹配相同元素的模板(在这种情况下为xsl:for-each)。但是,您可以使用xsl:apply-templates属性

解决此问题

考虑这个Employee

mode

将其替换为单个xsl:for-each,如此

  <xsl:for-each select="Employee[count(. | key('group-by-person', PERSON_ID)[1]) = 1]">
     <xsl:sort select="TM_LAST_NAME" />
     <!-- Inner code -->
  </xsl:for-each>

然后,将内部代码从for-each移动到模板匹配

xsl:apply-templates

您可以完全以相同的方式对嵌套的<xsl:apply-templates select="Employee[count(. | key('group-by-person', PERSON_ID)[1]) = 1]" mode="person" /> 重复这些步骤。

试试这个XSLT

<xsl:template match="Employee" mode="person">
    <!-- Inner code -->
</xsl:template>

在许多情况下,使用xsl:for-each不应该被视为“糟糕的形式”。要记住的是<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:key name="group-by-person" match="Employee" use="PERSON_ID" /> <xsl:key name="group-by-week" match="Employee" use="concat(PERSON_ID,'|',TM_WEEK)" /> <xsl:key name="group-by-day" match="Employee" use="concat(PERSON_ID,'|',TM_WEEK,'|',TM_BEGIN_DT)" /> <xsl:output method="html" indent="yes" /> <xsl:variable name="space"><xsl:text> </xsl:text></xsl:variable> <xsl:template match="/"> <html><body> <xsl:apply-templates /> </body></html> </xsl:template> <xsl:template match="Employees"> <xsl:apply-templates select="Employee[count(. | key('group-by-person', PERSON_ID)[1]) = 1]" mode="person"> <xsl:sort select="TM_LAST_NAME" /> </xsl:apply-templates> </xsl:template> <xsl:template match="Employee" mode="person"> <p><xsl:value-of select="TM_FIRST_NAME" /><xsl:value-of select="$space"/><xsl:value-of select="TM_LAST_NAME" /></p><br /> <!-- begin week grouping --> <xsl:apply-templates select="key('group-by-person', PERSON_ID)[count(. | key('group-by-week', concat(PERSON_ID,'|',TM_WEEK))[1]) = 1]" mode="week"> <xsl:sort select="TM_WEEK" data-type="number"/> </xsl:apply-templates> <!-- end week grouping --> <br/><xsl:text>person_id sum = </xsl:text> <xsl:value-of select="sum(key('group-by-person', PERSON_ID)/TM_CALCULATED_TIME)" /> <br/> </xsl:template> <xsl:template match="Employee" mode="week"> <p><xsl:value-of select="TM_WEEK" /></p><br/> <!-- begin day grouping --> <xsl:apply-templates select="key('group-by-week', concat(PERSON_ID,'|',TM_WEEK))[count(. | key('group-by-day', concat(PERSON_ID,'|',TM_WEEK,'|',TM_BEGIN_DT))[1]) = 1]" mode="day"> <xsl:sort select="TM_BEGIN_DT" /> </xsl:apply-templates> <!-- end day grouping --> <br/><xsl:text>weekly sum = </xsl:text> <xsl:value-of select="sum(key('group-by-week', concat(PERSON_ID,'|',TM_WEEK))/TM_CALCULATED_TIME)" /> <br/> </xsl:template> <xsl:template match="Employee" mode="day"> <xsl:value-of select="substring-before(TM_BEGIN_DT,'T')" /> <br/> <xsl:for-each select="key('group-by-day', concat(PERSON_ID,'|',TM_WEEK,'|',TM_BEGIN_DT))"> <p><xsl:value-of select="TM_BEGIN_TIME" /><xsl:value-of select="$space"/><xsl:value-of select="TM_END_TIME" /></p><br/> </xsl:for-each> <br/><xsl:text>daily sum = </xsl:text> <xsl:value-of select="sum(key('group-by-day', concat(PERSON_ID,'|',TM_WEEK,'|',TM_BEGIN_DT))/TM_CALCULATED_TIME)" /> <br/> </xsl:template> </xsl:stylesheet> 是映射构造,而不是循环。 (XSLT处理器可以自由地并行处理所选节点)。在你的情况下,使用xsl:for-each会导致过多的嵌套,这会使代码更难以阅读,但除此之外,它没有任何问题。