仅当使用XSLT在所有子元素中存在字符串时,才将字符串移动到子元素的头元素

时间:2013-10-07 21:47:13

标签: xslt

我的XML代码& XSLT代码 解释: 我试图用

从元素中移动字符串'2'
(tr[@type='detail'] and td[@column='1'])

到类别标题

(tr [@type='categoryhead' and level='2'])

非常感谢任何帮助 万分感谢

<!--=============My XML=============-->
<tbody xmlns="http://mynamespace.com">
  <tr layoutcode="" type="categoryhead" level="1" categorykey="2789" hierarchykey="4921">
    <td colname="1">Bonds</td>
  </tr>
  <tr layoutcode="" type="categoryhead" level="2" categorykey="3255" hierarchykey="4922">
    <td colname="1">Beverages</td>
  </tr>
  <tr layoutcode="" type="detail" level="3" securitymasterkey="41164">
    <td colname="1">Security_1(1,2)</td>
    <td colname="2">500</td>`enter code here`
    <td colname="3">330</td>
  </tr>
  <tr layoutcode="" type="detail" level="3" securitymasterkey="41167">
    <td colname="1">Security_4(1,2,3,4)</td>
    <td colname="2">10</td>
    <td colname="3">265</td>
  </tr>
  <tr layoutcode="" type="categorytotal" level="2" categorykey="3255" hierarchykey="4922">
    <td colname="1">Beverages</td>
    <td colname="2">530</td>
    <td colname="3">1,045</td>
  </tr>
  <tr layoutcode="" type="categorytotal" level="1" categorykey="2789" hierarchykey="4921">
    <td colname="1">TOTAL Bonds</td>
    <td colname="2">530</td>
    <td colname="3">1,045</td>
  </tr>

  <tr layoutcode="" type="categoryhead" level="1" categorykey="2936" hierarchykey="4921">
    <td colname="1">Options</td>
  </tr>
  <tr layoutcode="" type="categoryhead" level="2" categorykey="3248" hierarchykey="4922">
    <td colname="1">Agriculture</td>
  </tr>
  <tr layoutcode="" type="detail" level="3" securitymasterkey="41168">
    <td colname="1">Security_5(@,1)</td>
    <td colname="2">10</td>
    <td colname="3">890</td>
  </tr>
  <tr layoutcode="" type="detail" level="3" securitymasterkey="41168">
    <td colname="1">Security_5(@,2)</td>
    <td colname="2">10</td>
    <td colname="3">890</td>
  </tr>
  <tr layoutcode="" type="categorytotal" level="2" categorykey="3248" hierarchykey="4922">
    <td colname="1">Agriculture</td>
    <td colname="2">10</td>
    <td colname="3">890</td>
  </tr>
</tbody>

XSLT,我试图将带有(tr [@ type ='detail']和td [@ column ='1'])的元素中的字符串'2'移动到类别标题(tr [@type ='categoryhead'和level ='2'])

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:a="http://mynamespace.com" version="2.0">

  <!-- Global Variable -->
  <xsl:variable name="arg1" select="'2'"></xsl:variable>

  <!-- This identity template copies the document -->
  <xsl:template match="node() | @*">
    <xsl:copy>
      <xsl:apply-templates select="node() | @* "/>
    </xsl:copy>
  </xsl:template>


  <xsl:template match="a:tbody/a:tr[@type='categoryhead' and @level='2']/a:td">
    <xsl:for-each select="//a:tbody/a:tr[@type='detail']/a:td[@colname='1'][contains(.,$arg1)]">
      <xsl:variable name="IsFooted" select="contains(.,$arg1)"></xsl:variable>
      <xsl:value-of select="count(//a:tbody/a:tr[@type='detail']/a:td[@colname='1'][contains(.,$arg1)])"/>
      <xsl:choose>
        <xsl:when test="$IsFooted='true'">
          <xsl:value-of select="."/>
          <xsl:value-of select="concat('(',concat($arg1,')'))"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="."/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

所需的XML输出:

<tbody xmlns="http://mynamespace.com">
  <tr layoutcode="" type="categoryhead" level="1" categorykey="2789" hierarchykey="4921">
    <td colname="1">Bonds</td>
  </tr>
  <tr layoutcode="" type="categoryhead" level="2" categorykey="3255" hierarchykey="4922">
    <td colname="1">Beverages (2)</td>
  </tr>
  <tr layoutcode="" type="detail" level="3" securitymasterkey="41164">
    <td colname="1">Security_1(1)</td>
    <td colname="2">500</td>
    <td colname="3">330</td>
  </tr>
  <tr layoutcode="" type="detail" level="3" securitymasterkey="41167">
    <td colname="1">Security_4(1,3,4)</td>
    <td colname="2">10</td>
    <td colname="3">265</td>
  </tr>
  <tr layoutcode="" type="categorytotal" level="2" categorykey="3255" hierarchykey="4922">
    <td colname="1">Beverages</td>
    <td colname="2">530</td>
    <td colname="3">1,045</td>
  </tr>
  <tr layoutcode="" type="categorytotal" level="1" categorykey="2789" hierarchykey="4921">
    <td colname="1">TOTAL Bonds</td>
    <td colname="2">530</td>
    <td colname="3">1,045</td>
  </tr>

  <tr layoutcode="" type="categoryhead" level="1" categorykey="2936" hierarchykey="4921">
    <td colname="1">Options</td>
  </tr>
  <tr layoutcode="" type="categoryhead" level="2" categorykey="3248" hierarchykey="4922">
    <td colname="1">Agriculture</td>
  </tr>
  <tr layoutcode="" type="detail" level="3" securitymasterkey="41168">
    <td colname="1">Security_5(@,1)</td>
    <td colname="2">10</td>
    <td colname="3">890</td>
  </tr>
  <tr layoutcode="" type="detail" level="3" securitymasterkey="41168">
    <td colname="1">Security_5(@,2)</td>
    <td colname="2">10</td>
    <td colname="3">890</td>
  </tr>
  <tr layoutcode="" type="categorytotal" level="2" categorykey="3248" hierarchykey="4922">
    <td colname="1">Agriculture</td>
    <td colname="2">10</td>
    <td colname="3">890</td>
  </tr>
</tbody>

1 个答案:

答案 0 :(得分:0)

这里的术语不太清楚,因为在查看输出样本时,所发生的一切都是“(2)”被附加到特定的表格单元格,所以它并没有真正移动任何东西。

此外,您的问题标题提到了关于子元素的问题,但是看看XML结构,“细节”行实际上是“categoryhead”行的兄弟。这可能是问题所在;如何将“细节”行与关联的“categoryheader”关联起来。一种方法是使用密钥

<xsl:key name="row" 
         match="a:tr[@level != '1']" 
         use="generate-id(preceding-sibling::a:tr[@level=current()/@level - 1][1])" />

这将获取行(除了在级别1之外)并使用lowel @level属性将它们分组到前一行。

现在,对于你的模板匹配,因为你正在改变“td”元素,我会改变模板以匹配这样的元素,而不是“tr”元素

 <xsl:template match="a:tbody/a:tr[@type='categoryhead' and @level='2']/a:td[@colname='1']">

然后您可以使用该键来获取“子”元素,但不考虑所有子元素是否包含'2',而是反转逻辑并检查是否有任何子元素不包含'2' “

试试这个XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:a="http://composition.bowne.com/2010/v4" version="1.0">

  <!-- Global Variable -->
  <xsl:variable name="arg1" select="'2'"></xsl:variable>

  <xsl:key name="row" match="a:tr[@level != '1']" use="generate-id(preceding-sibling::a:tr[@level=current()/@level - 1][1])" />

  <!-- This identity template copies the document -->
  <xsl:template match="node() | @*">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="a:tbody/a:tr[@type='categoryhead' and @level='2']/a:td[@colname='1']">
      <xsl:variable name="IsMissing" select="key('row', generate-id(..))/a:td[@colname='1'][not(contains(text(), $arg1))]" />
      <xsl:choose>
        <xsl:when test="not($IsMissing)">
          <xsl:value-of select="."/>
          <xsl:value-of select="concat('(',concat($arg1,')'))"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="."/>
        </xsl:otherwise>
      </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

另外,XSLT中的命名空间与XML中的命名空间不匹配。你需要这些来匹配这个,但我认为这是一个错字。

编辑:要从“详细信息”行中删除“2”,请尝试添加以下模板。 'isMissing'变量有点混乱,因为它必须首先找到相关的'categoryhead'。另请注意,它使用“替换”,仅在XSLT 2.0中可用。

  <xsl:template match="a:tbody/a:tr[@type='detail']/a:td[@colname='1']">
    <xsl:variable name="parentLevel" select="../@level - 1" />
    <xsl:variable name="IsMissing" select="key('row', generate-id(../preceding-sibling::a:tr[@level=$parentLevel][1]))/a:td[@colname='1'][not(contains(text(), $arg1))]" />
      <xsl:choose>
        <xsl:when test="not($IsMissing)">
          <xsl:value-of select="replace(., concat(',', $arg1), '')"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="."/>
        </xsl:otherwise>
      </xsl:choose>
  </xsl:template>