本文介绍了子字符串上的XSL Muenchian方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将一些XML输出转换为一个等级表(与水文学相关),该等级表包括从顶部穿过的百分之一值和从向下穿过的十分之一值.我遇到的问题是,我似乎无法通过使用ht属性上的子字符串来对唯一值进行排序.

I'm trying to transform some XML output to a rating table (hydrology related) which consists of the hundredths values going across the top and the tenths values going down. The problem I'm running into is that I can't seem to sort for the unique values by using a substring on the ht attributes.

以下是XML输出的示例:

Here is a sample of the XML output:

<env:Envelope>
<env:Header/>
<env:Body>
<RatingTableUpdate>
  <Gauge xmlns="" type="STORAGE" id="123">
    <Input input="0">
      <Conv ht="19.76" cap="5040" />
      <Conv ht="19.77" cap="5045" />
      <Conv ht="19.78" cap="5051" />
      <Conv ht="19.79" cap="5057" />
      <Conv ht="19.80" cap="5063" />
      <Conv ht="19.81" cap="5069" />
      <Conv ht="19.82" cap="5074" />
      <Conv ht="19.83" cap="5080" />
      <Conv ht="19.84" cap="5086" />
      <Conv ht="19.85" cap="5092" />
      <Conv ht="19.86" cap="5098" />
      <Conv ht="19.87" cap="5104" />
      <Conv ht="19.88" cap="5109" />
      <Conv ht="19.89" cap="5115" />
      <Conv ht="19.90" cap="5121" />
      <Conv ht="19.91" cap="5127" />
      <Conv ht="19.92" cap="5133" />
      <Conv ht="19.93" cap="5138" />
    </Input>
  </Gauge>
</RatingTableUpdate>
</env:Body>
</env:Envelope>

输出应如下所示:

GH    0.00  0.01  0.02  0.03  0.04  0.05  0.06  0.07  0.08  0.09
19.7                                      5040  5045  5051  5057
19.8  5063  5069  5074  5080  5086  5092  5098  5104  5109  5115
19.9  5121  5127  5133  5138

我能够在正确的列中获得cap属性,但无法获得GH列(ht属性已删除百分之一的ht属性),每行仅显示一次.我得到这样的东西:

I'm able to get the cap attributes in the correct column, but can't get the GH column (ht attribute with hundredths values dropped) to only display once per row. I get something like this:

GH    0.00  0.01  0.02  0.03  0.04  0.05  0.06  0.07  0.08  0.09
19.7                                      5040
                                                5045
                                                      5051
                                                            5057
19.8  5063
            5069
                  5074
                        5080
                              5086
                                    5092
                                          5098
                                                5104
                                                      5109
                                                            5115
19.9  5121
            5127
                  5133
                        5138

这是我的xsl部分,用于格式化该部分. xsl:choose似乎对这些列很有效.我已经尝试过Muenchian方法,但无法完全正确(很难将其与子字符串键一起使用).

Here's my section of xsl that formats this section. The xsl:choose seems to work well for the columns. I've tried the Muenchian method but can't get it quite right (having a hard time getting it to work with a substring key).

这是最好的方法,还是有另一种方法来使给定子字符串的每一行仅显示一次(19.76、19.77、19.78、19.79值分别为19.7)?像示例一样从非零值开始,所以我不能只使用百分之一的0值开始一个组,而使用9的值结束一个组.

Is this the best method, or is there another way to get each row to display only once for the given substring (19.7 once for 19.76, 19.77, 19.78, 19.79 values)? The ratings commonly start at non-zero values like the example, so I can't just use the hundredth 0 values to start a group and 9 to end a group.

<xsl:for-each select="env:Envelope/env:Body/RatingTableUpdate/Gauge">

<table width="100%">
<tr class="site">
  <td width="150px">Site ID: <u><xsl:value-of select="@id" /></u></td>
  <td>Site Name: <u><xsl:value-of select="@idname" /></u></td>
  <td>Type: <u><xsl:value-of select="@type" /></u></td>
</tr>
</table>

<table width="100%">
  <tr class="tbldata">
    <th rowspan="1" class="tbldataheader">GH</th>
    <th rowspan="1" class="tbldataheader">0.00</th>
    <th rowspan="1" class="tbldataheader">0.01</th>
    <th rowspan="1" class="tbldataheader">0.02</th>
    <th rowspan="1" class="tbldataheader">0.03</th>
    <th rowspan="1" class="tbldataheader">0.04</th>
    <th rowspan="1" class="tbldataheader">0.05</th>
    <th rowspan="1" class="tbldataheader">0.06</th>
    <th rowspan="1" class="tbldataheader">0.07</th>
    <th rowspan="1" class="tbldataheader">0.08</th>
    <th rowspan="1" class="tbldataheader">0.09</th>
  </tr>

  <xsl:for-each select="./Input/Conv">
    <tr class="tbldata">

      <xsl:choose>
        <xsl:when test="substring(@ht,string-length(@ht),1) = 0">
          <td class="ifrtext"><xsl:value-of select="substring(@ht,1,string-length(@ht)-1)" /></td>
        </xsl:when>
        <xsl:otherwise>
          <td class="ifrtext"></td>
        </xsl:otherwise>
      </xsl:choose>
       <xsl:choose>
        <xsl:when test="substring(@ht,string-length(@ht),1) = 0">
          <td class="ifrtext"><xsl:value-of select="@cap" /></td>
        </xsl:when>
        <xsl:otherwise>
          <td class="ifrtext"></td>
        </xsl:otherwise>
      </xsl:choose>
      <xsl:choose>
        <xsl:when test="substring(@ht,string-length(@ht),1) = 1">
          <td class="ifrtext"><xsl:value-of select="@cap" /></td>
        </xsl:when>
        <xsl:otherwise>
          <td class="ifrtext"></td>
        </xsl:otherwise>
      </xsl:choose>
      <xsl:choose>
        <xsl:when test="substring(@ht,string-length(@ht),1) = 2">
          <td class="ifrtext"><xsl:value-of select="@cap" /></td>
        </xsl:when>
        <xsl:otherwise>
          <td class="ifrtext"></td>
        </xsl:otherwise>
      </xsl:choose>
      <xsl:choose>
        <xsl:when test="substring(@ht,string-length(@ht),1) = 3">
          <td class="ifrtext"><xsl:value-of select="@cap" /></td>
        </xsl:when>
        <xsl:otherwise>
          <td class="ifrtext"></td>
        </xsl:otherwise>
      </xsl:choose>
      <xsl:choose>
        <xsl:when test="substring(@ht,string-length(@ht),1) = 4">
          <td class="ifrtext"><xsl:value-of select="@cap" /></td>
        </xsl:when>
        <xsl:otherwise>
          <td class="ifrtext"></td>
        </xsl:otherwise>
      </xsl:choose>
      <xsl:choose>
        <xsl:when test="substring(@ht,string-length(@ht),1) = 5">
          <td class="ifrtext"><xsl:value-of select="@cap" /></td>
        </xsl:when>
        <xsl:otherwise>
          <td class="ifrtext"></td>
        </xsl:otherwise>
      </xsl:choose>
      <xsl:choose>
        <xsl:when test="substring(@ht,string-length(@ht),1) = 6">
          <td class="ifrtext"><xsl:value-of select="@cap" /></td>
        </xsl:when>
        <xsl:otherwise>
          <td class="ifrtext"></td>
        </xsl:otherwise>
      </xsl:choose>
      <xsl:choose>
        <xsl:when test="substring(@ht,string-length(@ht),1) = 7">
          <td class="ifrtext"><xsl:value-of select="@cap" /></td>
        </xsl:when>
        <xsl:otherwise>
          <td class="ifrtext"></td>
        </xsl:otherwise>
      </xsl:choose>
      <xsl:choose>
        <xsl:when test="substring(@ht,string-length(@ht),1) = 8">
          <td class="ifrtext"><xsl:value-of select="@cap" /></td>
        </xsl:when>
        <xsl:otherwise>
          <td class="ifrtext"></td>
        </xsl:otherwise>
      </xsl:choose>
      <xsl:choose>
        <xsl:when test="substring(@ht,string-length(@ht),1) = 9">
          <td class="ifrtext"><xsl:value-of select="@cap" /></td>
        </xsl:when>
        <xsl:otherwise>
          <td class="ifrtext"></td>
        </xsl:otherwise>
      </xsl:choose>
    </tr>
  </xsl:for-each>
</table>
</xsl:for-each>

谢谢,马特

推荐答案

此转换:

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

 <xsl:key name="kValByTenths" match="Conv"
      use="substring(@ht, 1, 4)"/>

 <xsl:key name="kCapFromHt" match="@cap"
      use="../@ht"/>

 <xsl:template match="Input">
  <table>
   <xsl:for-each select=
    "Conv[generate-id()
         =
          generate-id(key('kValByTenths',substring(@ht, 1, 4))[1])
          ]">
     <xsl:variable name="vKey" select="substring(@ht, 1, 4)"/>
     <tr>
      <td><xsl:value-of select="$vKey"/></td>

      <xsl:for-each select=
       "(//node() | //namespace::*)[not(position() > 10)]">
        <xsl:variable name="vPos" select="position()"/>
        <td>
         <xsl:value-of select="key('kCapFromHt', concat($vKey,$vPos -1))"/>
        </td>
      </xsl:for-each>
     </tr>
    </xsl:for-each>
   </table>
 </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档(已更正为格式正确的XML文档):

when applied on the provided XML document (corrected to be made well-formed XML document):

<env:Envelope xmlns:env="some:env">
    <env:Header/>
    <env:Body>
        <RatingTableUpdate>
            <Gauge xmlns="" type="STORAGE" id="123">
                <Input input="0">
                    <Conv ht="19.76" cap="5040" />
                    <Conv ht="19.77" cap="5045" />
                    <Conv ht="19.78" cap="5051" />
                    <Conv ht="19.79" cap="5057" />
                    <Conv ht="19.80" cap="5063" />
                    <Conv ht="19.81" cap="5069" />
                    <Conv ht="19.82" cap="5074" />
                    <Conv ht="19.83" cap="5080" />
                    <Conv ht="19.84" cap="5086" />
                    <Conv ht="19.85" cap="5092" />
                    <Conv ht="19.86" cap="5098" />
                    <Conv ht="19.87" cap="5104" />
                    <Conv ht="19.88" cap="5109" />
                    <Conv ht="19.89" cap="5115" />
                    <Conv ht="19.90" cap="5121" />
                    <Conv ht="19.91" cap="5127" />
                    <Conv ht="19.92" cap="5133" />
                    <Conv ht="19.93" cap="5138" />
                </Input>
            </Gauge>
        </RatingTableUpdate>
    </env:Body>
</env:Envelope>

产生想要的东西(不带装饰),得到正确的结果:

<table>
   <tr>
      <td>19.7</td>
      <td/>
      <td/>
      <td/>
      <td/>
      <td/>
      <td/>
      <td>5040</td>
      <td>5045</td>
      <td>5051</td>
      <td>5057</td>
   </tr>
   <tr>
      <td>19.8</td>
      <td>5063</td>
      <td>5069</td>
      <td>5074</td>
      <td>5080</td>
      <td>5086</td>
      <td>5092</td>
      <td>5098</td>
      <td>5104</td>
      <td>5109</td>
      <td>5115</td>
   </tr>
   <tr>
      <td>19.9</td>
      <td>5121</td>
      <td>5127</td>
      <td>5133</td>
      <td>5138</td>
      <td/>
      <td/>
      <td/>
      <td/>
      <td/>
      <td/>
   </tr>
</table>

说明:

  1. 正确使用 Muenchian分组方法 ,其中Conv元素由其ht属性的字符串值的前4个字符索引.

  1. Proper use of the Muenchian grouping method where a Conv element is indexed by the first 4 characters of the string vaue of its ht attribute.

正确使用 Piez方法 N次非递归迭代.

Proper use of the Piez method for non-recursive iteration N times.

更新:

OP报告说,由于MSXML3中的错误,他在使用IE 8时无法获得正确的结果.

The OP has reported that due to a bug in MSXML3 he cannot get the correct result when using IE 8.

这是经过修改的解决方案,也可以与MSXML3/IE 8一起使用:

Here is a modified solution that also works OK with MSXML3 / IE 8:

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

 <xsl:key name="kValByTenths" match="Conv"
      use="substring(@ht, 1, 4)"/>

 <xsl:variable name="vConvs" select="//Conv"/>

 <xsl:template match="Input">
  <table>
   <xsl:for-each select=
    "Conv[generate-id()
         =
          generate-id(key('kValByTenths',substring(@ht, 1, 4))[1])
          ]">
     <xsl:variable name="vKey" select="substring(@ht, 1, 4)"/>
     <tr>
      <td><xsl:value-of select="$vKey"/></td>

      <xsl:for-each select=
       "(//node() | //namespace::*)[not(position() > 10)]">
        <xsl:variable name="vPos" select="position()"/>

        <td>
         <xsl:value-of select=
         "$vConvs[substring-after(@ht, $vKey) = $vPos]/@cap"/>
        </td>
      </xsl:for-each>
     </tr>
    </xsl:for-each>
   </table>
 </xsl:template>
</xsl:stylesheet>

这篇关于子字符串上的XSL Muenchian方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-06 04:49