【问题标题】:XSLT copy parent element with attributes and change child elementsXSLT 使用属性复制父元素并更改子元素
【发布时间】:2020-09-26 11:33:59
【问题描述】:

这块HTML表格

<tr>
  <td>
    <p>only one cell without break</p>
  </td>
  <td colspan="3">
    <p>text 1</p>
    <p>text 2</p>
    <p>text 3</p>
  </td>
  <td colspan="3">
    <list>
      <list-item>
        <p>list item 1</p>
      </list-item>
      <list-item>
        <p>list item 2</p>
      </list-item>
      <list-item>
        <p>list item 3</p>
      </list-item>
    </list>
  </td>
</tr>

必须翻译成:

<tr>
  <td>
    only one cell without break
  </td>
  <td colspan="3">
    text 1<break/>
    text 2<break/>
    text 3
  </td>
  <td colspan="3">
    <list>
      <list-item>
        <p>list item 1</p>
      </list-item>
      <list-item>
        <p>list item 2</p>
      </list-item>
      <list-item>
        <p>list item 3</p>
      </list-item>
    </list>
  </td>
</tr>

我正在使用这段 XSLT 代码:

  <xsl:template match="td">
    <td>
      <xsl:for-each select="p">
        <xsl:apply-templates/> 
        <xsl:if test="position() != last()">
          <break/>
        </xsl:if>
      </xsl:for-each>
      <xsl:apply-templates select="* except p"/> 
    </td>
  </xsl:template>

我必须选择&lt;td&gt; 作为父节点,这样我就可以用&lt;break/&gt; 标记更改一个单元格内的所有&lt;p&gt; 标记,用于除最后一个之外的所有元素,其中一个单元格内有多个&lt;p&gt; .如果单元格内只有一个&lt;p&gt;,则&lt;p&gt; 标签也必须删除,但&lt;break/&gt; 不需要添加。所有其他标签(即列表)保持不变。它有效,但我失去了这段代码的“colspan”属性。

出于明显的原因(手动设置&lt;td&gt;)属性 colspan 没有从父级复制。

是否有可能以某种方式“修复”代码并将具有所有属性的父 &lt;td&gt; 元素复制到输出表?

【问题讨论】:

  • “我也必须使用 for-each 循环”是一些家庭作业要求吗?或者是什么让你相信你需要使用 for-each?从长远来看,使用应用模板和模板匹配编写推送样式代码可以轻松完成工作。
  • 我更新了代码,因此它反映了为什么在这种情况下必须使用 for-each(在我看来)的真正问题。如果有其他方法,我会很高兴。

标签: xslt


【解决方案1】:

样本所代表的唯一变换是

  <xsl:template match="tr/td/p">
      <x>
          <xsl:apply-templates select="@* | node()"/>
      </x>
  </xsl:template>

其余的可以通过身份转换处理(例如 XSLT 3 中的 &lt;xsl:mode on-no-match="shallow-copy"/&gt; 或 XSLT 2 或 1 中的模板拼写)。

编辑问题后,任务完全不同,但我认为仍然需要通过推送样式应用模板和模板匹配来解决,您想要的两个转换表示为两个模板:

  <xsl:template match="tr/td/p">
      <xsl:apply-templates/>
  </xsl:template>
  
  <xsl:template match="tr/td/p[not(position() = last())]">
      <xsl:apply-templates/>
      <break/>
  </xsl:template>

其余的将由身份转换处理。

https://xsltfiddle.liberty-development.net/pNmCztv

【讨论】:

  • 请检查上面的更新示例,它反映了这种情况下的整个问题。
  • @Futurion,我已经编辑了答案以满足您的新要求。在我看来,仍然不需要在模板中使用 for-each 并且不依赖于身份转换然后为您想要执行的更改添加模板。
  • 好吧,这对我来说完全是另一个层次。它看起来很简单,但同样,我永远不会弄明白。当然,它工作得非常好。非常感谢!
  • 也许只是我发现的另一件事。我使用“Oxygen XML”进行编辑,它抱怨这两个模板带有“模糊规则匹配”警告。可能是因为第一个模板还解决了第二个模板解决的一些元素。这是否也可以以某种方式修复?将第一个模板更改为&lt;xsl:template match="tr/td/p[position() = last()]"&gt; 就足够了吗?
  • @Futurion,该 oXygen 消息是一个警告,如果您不确定模板优先级,这可能会有所帮助,但由于相同优先级中的最后一个获胜(在现有实现中),我提出的建议适用于大多数用例。您当然可以添加更精确的条件来区分情况或在模板上提供明确的priority 设置以避免警告或在XSLT 3 中xsl:mode 上也有该选项: `。
猜你喜欢
  • 1970-01-01
  • 2016-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-26
  • 1970-01-01
相关资源
最近更新 更多