【问题标题】:Create the <entry><morerows/></entry> element in the <row> element在 <row> 元素中创建 <entry><morerows/></entry> 元素
【发布时间】:2021-12-24 06:14:28
【问题描述】:

需要创建&lt;entry&gt;&lt;morerows/&gt;&lt;/entry&gt;

  1. 如果&lt;entry&gt;/@morerows 有以下兄弟&lt;row&gt; 元素
  2. 在需要检查&lt;entry&gt;/@morerows的位置之前,然后在下面的兄弟&lt;row&gt;中创建&lt;entry&gt;&lt;morerows/&gt;&lt;/entry&gt;
  3. 如果您在输入中看到第二个元素中的&lt;entry&gt; 元素较少,因为在第一个元素中使用了@morerows 属性(@morerows 属性表示&lt;rowspan&gt; 元素概念)

示例:假设&lt;entry&gt;/@morerows的位置是第6位,那么需要在following-sibling 6th place entry中的第6位位置创建下一个兄弟&lt;entry&gt;&lt;morerows/&gt;&lt;/entry&gt; 请帮助我完成上述具有挑战性的任务并提前感谢

输入xml:

            <table>
                <tgroup>
                    <thead>
                        <row>
                            <entry><p></p></entry>
                            <entry namest="col2" nameend="col3"><p>Class A Common</p></entry>
                            <entry namest="col4" nameend="col5"><p>Class B Common</p></entry>
                            <entry morerows="1"><p>Additional</p></entry>
                            <entry morerows="1"><p>Retained</p></entry>
                            <entry morerows="1"><p>Accumulated</p></entry>
                            <entry namest="col9" nameend="col10"><p>Class A 1</p></entry>
                            <entry morerows="1"><p>Noncontrolling</p></entry>
                            <entry morerows="1"><p>Total</p></entry>
                        </row>
                        <row>
                            <entry><p>content here</p></entry>
                            <entry><p>content 1</p></entry>
                            <entry><p>content 2</p></entry>
                            <entry><p>content 1</p></entry>
                            <entry><p>content 2</p></entry>
                            
                            <entry><p>content 1</p></entry>
                            <entry><p>content 2</p></entry>
                            
                        </row>
                    </thead>
                </tgroup>
            </table>

预期输出:

<table>
    <tgroup>
        <thead>
            <row>
                <entry><p></p></entry>
                <entry namest="col2" nameend="col3"><p>Class A Common</p></entry>
                <entry namest="col4" nameend="col5"><p>Class B Common</p></entry>
                <entry morerows="1"><p>Additional</p></entry>
                <entry morerows="1"><p>Retained</p></entry>
                <entry morerows="1"><p>Accumulated</p></entry>
                <entry namest="col9" nameend="col10"><p>Class A 1</p></entry>
                <entry morerows="1"><p>Noncontrolling</p></entry>
                <entry morerows="1"><p>Total</p></entry>
            </row>
            <row>
                <entry><p>content here</p></entry>
                <entry><p>content 1</p></entry>
                <entry><p>content 2</p></entry>
                <entry><p>content 1</p></entry>
                <entry><p>content 2</p></entry>
                
                <entry><morerows/></entry>
                <entry><morerows/></entry>
                <entry><morerows/></entry>
                
                <entry><p>content 1</p></entry>
                <entry><p>content 2</p></entry>
                
                <entry><morerows/></entry>
                <entry><morerows/></entry>
            </row>
        </thead>
    </tgroup>
</table>

【问题讨论】:

  • 请您编辑您的示例并删除所有&lt;colspec.../&gt; 元素吗?他们分散了 entry 和 morerows 元素的注意力……滚动太多了 :) 谢谢。
  • 单个示例并不能很好地说明需求,但请查看现有的表规范化示例。
  • 嗨 @ZachYoung 我删除了 元素,你能解决这个问题吗,这个非常具有挑战性的任务。
  • 谢谢。我同意马丁的观点……我很难理解应该发生什么。在您的示例中,&lt;entry&gt;&lt;morerows/&gt;&lt;/entry&gt; 的最终位置似乎与&lt;entry morerows... /&gt; 的位置无关...您的示例直观地显示了它们应该结束的位置,但这只是因为空格。

标签: xml xslt


【解决方案1】:

我写了几个步骤的管道(使用几种模式),第一个将您的输入转换为基于rowspan/colspan的转换格式https://stackoverflow.com/a/36106927/252228中的解决方案,基于已经提到的https://andrewjwelch.com/code/xslt/table/table-normalization.html,使用,然后基本上使用该解决方案中的模板,仅匹配/选择 rowentry 而不是 trth/td 并确保最终模式删除辅助行跨度属性并填写&lt;entry&gt;&lt;morerows/&gt;&lt;/entry&gt;元素:

<?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="#all"
    version="3.0">

  <xsl:mode on-no-match="shallow-copy"/>
  
  <xsl:key name="col" match="table/tgroup/colspec" use="@colname"/>
  
  <xsl:mode name="html-row-col-span" on-no-match="shallow-copy"/>
  
  <xsl:template mode="html-row-col-span" match="entry/@morerows">
    <xsl:next-match/>
    <xsl:attribute name="rowspan" select=". + 1"/>
  </xsl:template>
  
  <xsl:template mode="html-row-col-span" match="entry[@namest and @nameend]/@namest">
    <xsl:next-match/>
    <xsl:attribute name="colspan" select="key('col', ../@nameend, ancestor::tgroup)/@colnum - key('col', ., ancestor::tgroup)/@colnum + 1"/>
  </xsl:template>

  <xsl:mode name="colspan" on-no-match="shallow-copy"/>
  
  <xsl:mode name="rowspan" on-no-match="shallow-copy"/>
  
  <xsl:mode name="final-cleanup" on-no-match="shallow-copy"/>

  <xsl:output method="xml" indent="yes" suppress-indentation="entry"/>
  
  <xsl:template match="table/tgroup">
    <xsl:variable name="row-and-colspan">
      <xsl:apply-templates select="." mode="html-row-col-span"/>
    </xsl:variable>
    <xsl:variable name="tgroup_with_no_colspans">
        <xsl:apply-templates select="$row-and-colspan" mode="colspan" />
    </xsl:variable>
    <xsl:variable name="tgroup_with_normalized_rowspans">
        <xsl:apply-templates select="$tgroup_with_no_colspans" mode="rowspan" />
    </xsl:variable>
    <xsl:apply-templates select="$tgroup_with_normalized_rowspans" mode="final-cleanup"/>
  </xsl:template>
  
  <xsl:template mode="colspan" match="entry[@colspan]">
    <xsl:next-match/>
    <xsl:for-each select="2 to @colspan">
      <entry><col-span-filler/></entry>
    </xsl:for-each>
  </xsl:template>
  
  <xsl:template mode="colspan" match="@colspan"/>

  <xsl:template match="thead | tbody" mode="rowspan">
      <xsl:copy>
          <xsl:copy-of select="row[1]"/>
          <xsl:apply-templates select="row[2]" mode="rowspan">
              <xsl:with-param name="previousRow" select="row[1]"/>
          </xsl:apply-templates>
      </xsl:copy>
  </xsl:template>

  <xsl:template match="row" mode="rowspan">
    <xsl:param name="previousRow" as="element()" />

    <xsl:variable name="currentRow" select="." />

    <xsl:variable name="normalizedEntries">
        <xsl:for-each select="$previousRow/*">
            <xsl:choose>
                <xsl:when test="@rowspan &gt; 1">
                    <xsl:copy>
                        <xsl:attribute name="rowspan">
                            <xsl:value-of select="@rowspan - 1" />
                        </xsl:attribute>
                    </xsl:copy>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:copy-of select="$currentRow/entry[1 + count(current()/preceding-sibling::*[not(@rowspan) or (@rowspan = 1)])]" />
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each>
    </xsl:variable>

    <xsl:variable name="newRow" as="element(row)">
        <xsl:copy>
            <xsl:copy-of select="$currentRow/@*" />
            <xsl:copy-of select="$normalizedEntries" />
        </xsl:copy>
    </xsl:variable>

    <xsl:copy-of select="$newRow" />

    <xsl:apply-templates select="following-sibling::row[1]" mode="rowspan">
        <xsl:with-param name="previousRow" select="$newRow" />
    </xsl:apply-templates>
  </xsl:template> 
  
  <xsl:template mode="final-cleanup" match="entry[col-span-filler] | entry[@morerows]/@rowspan"/>
  
  <xsl:template mode="final-cleanup" match="entry[@rowspan and not(@morerows)]">
    <xsl:copy>
      <morerows/>
    </xsl:copy>
  </xsl:template>
  
</xsl:stylesheet>

代码使用 XSLT 3,例如xsl:mode,但您也可以将其编写为 XSLT 2,就像 Andrew Welch 的解决方案和我对之前 StackOverflow 帖子的改编一样。在 XSLT 3 中使用 xsl:iterate 可能还可以更有效地重新实现所使用的兄弟递归。

如果使用使用累加器而不是键和两个嵌套 xsl:iterate 的 SaxonCS 或 Saxon EE,那么这里是一个纯 XSLT 3 解决方案也适用于流:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="3.0"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:map="http://www.w3.org/2005/xpath-functions/map"
  exclude-result-prefixes="#all"
  expand-text="yes">

  <xsl:output method="xml" indent="yes" suppress-indentation="entry"/>
  
  <xsl:accumulator name="colnums" as="map(xs:string, xs:integer)" initial-value="map{}" streamable="yes">
    <xsl:accumulator-rule
      match="tgroup" select="map{}"/>
    <xsl:accumulator-rule
      match="colspec"
      select="map:put($value, xs:string(@colname), xs:integer(@colnum))"/>
  </xsl:accumulator>
  
  <xsl:mode name="fill-rowspan-colspan" on-no-match="shallow-copy" use-accumulators="colnums" streamable="yes"/>
  
  <xsl:template mode="fill-rowspan-colspan" match="entry">
    <xsl:next-match/>
    <xsl:iterate select=".[@namest] ! (1 to (accumulator-before('colnums')(@nameend)!xs:integer(.) - accumulator-before('colnums')(@namest)!xs:integer(.)))">
      <entry>
        <col-span-filler/>
      </entry>
    </xsl:iterate>
  </xsl:template>
  
  <xsl:template mode="fill-rowspan-colspan" match="entry/@morerows">
    <xsl:next-match/>
    <xsl:attribute name="rowspan" select=". + 1"/>
  </xsl:template>

  <xsl:mode on-no-match="shallow-copy" use-accumulators="colnums" streamable="yes"/>
  
  <xsl:template match="thead | tbody">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:iterate select="row">
        <xsl:param name="prev-row" as="element(row)?" select="()"/>
        <xsl:variable name="new-row" as="element(row)">
          <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates select="entry" mode="fill-rowspan-colspan"/>
          </xsl:copy>
        </xsl:variable>
        <xsl:variable name="new-row" as="element(row)">
          <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:choose>
              <xsl:when test="not($prev-row)">
                <xsl:copy-of select="$new-row/*"/>
              </xsl:when>
              <xsl:otherwise>
                <xsl:iterate select="$prev-row!entry">
                  <xsl:choose>
                      <xsl:when test="@rowspan > 1">
                        <xsl:copy>
                          <xsl:attribute name="rowspan" select="@rowspan - 1"/>
                        </xsl:copy>
                      </xsl:when>
                      <xsl:otherwise>
                        <xsl:copy-of select="$new-row/entry[1 + count(current()/preceding-sibling::*[not(@rowspan) or @rowspan = 1])]"/>
                      </xsl:otherwise>                
                  </xsl:choose>
                </xsl:iterate>            
              </xsl:otherwise>
            </xsl:choose>
          </xsl:copy>
        </xsl:variable>
        <xsl:apply-templates select="$new-row" mode="clean-up"/>
        <xsl:next-iteration>
          <xsl:with-param name="prev-row" select="$new-row"/>
        </xsl:next-iteration>
      </xsl:iterate>
    </xsl:copy>
  </xsl:template>
  
  <xsl:mode name="clean-up" on-no-match="shallow-copy"/>
  
  <xsl:template mode="clean-up" match="entry[@rowspan = 1]">
    <xsl:copy>
      <morerows/>
    </xsl:copy>
  </xsl:template>
  
  <xsl:template mode="clean-up" match="entry[col-span-filler] | entry/@rowspan"/>

  <xsl:template match="/" name="xsl:initial-template">
    <xsl:next-match/>
    <xsl:comment>Run with {system-property('xsl:product-name')} {system-property('xsl:product-version')} {system-property('Q{http://saxon.sf.net/}platform')}</xsl:comment>
  </xsl:template>

</xsl:stylesheet>

注意:两个呈现的样式表都假定您第一次编辑问题的 colspec 部分存在于输入样本中,否则无法计算带有 @namest@nameend 属性的 entry 的 colspan 部分。

【讨论】:

  • 今天我发布了正确的输入,请看这个并帮助我@martin
  • @KitaAnsari,这是什么意思,“今天我发布了正确的输入”?您之前是否发布了一些您现在认为不正确的输入样本,并期望我们调整任何答案以适应新的输入样本,即使没有显示和解释您预期的“正确(ed)”输出是什么?如果唯一缺少的是新创建的entry 上的col 索引属性,则将它们的模板更改为&lt;xsl:template mode="clean-up" match="entry[@rowspan = 1]"&gt;&lt;xsl:copy&gt;&lt;xsl:attribute name="col"&gt;&lt;xsl:number/&gt;&lt;/xsl:attribute&gt;&lt;morerows/&gt;&lt;/xsl:copy&gt;&lt;/xsl:template&gt;
猜你喜欢
  • 2021-12-21
  • 2021-12-16
  • 1970-01-01
  • 2021-08-30
  • 2016-07-30
  • 2012-03-24
  • 1970-01-01
  • 2018-05-21
  • 1970-01-01
相关资源
最近更新 更多