You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于子节点复制父节点的XSLT实现需求及疑问

Solution to Split Tree Nodes by Leaf Position in XSLT

Got it, let's break down how to solve this problem. Your current code is already creating the right number of tree copies, but since you're using <xsl:copy-of>, you can't modify the tree structure (like removing extra leaves or the uId attribute) during the copy. We need to switch to a top-down template matching approach (starting from tree and working down to leaf) so we can control each node's output as we go.

Key Changes Needed:

  • Instead of copying the entire tree directly, we'll process the tree node, exclude the uId attribute, and pass along the index of the leaf we want to keep.
  • For each branch, we'll process its leaves node and only retain the Nth leaf (matching the current copy index).
  • Adjust the recursive copy template to trigger this top-down processing instead of using <xsl:copy-of>.

Updated XSLT Code

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:exsl="http://exslt.org/common"
                exclude-result-prefixes="exsl"
                version="1.0">

  <!-- Main template: trigger the copy process for the original tree -->
  <xsl:template match="tree">
    <xsl:variable name="leaf-count" select="count((.//leaves)[1]/leaf)" />
    <xsl:call-template name="generate-tree-copies">
      <xsl:with-param name="current-index" select="1" />
      <xsl:with-param name="total-copies" select="$leaf-count" />
      <xsl:with-param name="original-tree" select="." />
    </xsl:call-template>
  </xsl:template>

  <!-- Recursive template to generate each tree copy -->
  <xsl:template name="generate-tree-copies">
    <xsl:param name="current-index" />
    <xsl:param name="total-copies" />
    <xsl:param name="original-tree" />

    <xsl:if test="$current-index <= $total-copies">
      <!-- Process the original tree, passing the index to keep -->
      <xsl:apply-templates select="$original-tree">
        <xsl:with-param name="keep-leaf-index" select="$current-index" />
      </xsl:apply-templates>

      <!-- Recurse for the next copy -->
      <xsl:call-template name="generate-tree-copies">
        <xsl:with-param name="current-index" select="$current-index + 1" />
        <xsl:with-param name="total-copies" select="$total-copies" />
        <xsl:with-param name="original-tree" select="$original-tree" />
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

  <!-- Template to process tree node: exclude uId, copy other attributes/children -->
  <xsl:template match="tree">
    <xsl:param name="keep-leaf-index" />
    <tree>
      <!-- Copy all attributes except uId -->
      <xsl:copy-of select="@*[local-name() != 'uId']" />
      <!-- Process child branches with the leaf index parameter -->
      <xsl:apply-templates select="branch">
        <xsl:with-param name="keep-leaf-index" select="$keep-leaf-index" />
      </xsl:apply-templates>
    </tree>
  </xsl:template>

  <!-- Template to process branch nodes: copy and pass the leaf index to leaves -->
  <xsl:template match="branch">
    <xsl:param name="keep-leaf-index" />
    <xsl:copy>
      <xsl:copy-of select="@*" />
      <!-- Process leaves with the index parameter -->
      <xsl:apply-templates select="leaves">
        <xsl:with-param name="keep-leaf-index" select="$keep-leaf-index" />
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>

  <!-- Template to process leaves: only keep the Nth leaf -->
  <xsl:template match="leaves">
    <xsl:param name="keep-leaf-index" />
    <leaves>
      <!-- Select only the leaf at the specified position -->
      <xsl:copy-of select="leaf[$keep-leaf-index]" />
    </leaves>
  </xsl:template>

  <!-- Fallback template: copy any other nodes/attributes not explicitly matched -->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()" />
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

How This Works:

  1. Top-Down Processing: We start with the tree node, create copies by recursively calling generate-tree-copies. For each copy, we pass the index of the leaf we want to retain.
  2. Tree Attribute Control: The tree template copies all attributes except uId, so each output tree loses that attribute.
  3. Leaf Filtering: When processing leaves, we only select the leaf at the keep-leaf-index position, ensuring each tree copy has exactly one leaf per branch.
  4. Fallback Template: The final template ensures any other nodes/attributes (like branch names, leaf content) are copied as-is, so we don't lose any other data.

Example Input/Output:

Input XML:

<tree uId="tree1">
  <branch name="branch1">
    <leaves>
      <leaf>Leaf 1-1</leaf>
      <leaf>Leaf 1-2</leaf>
    </leaves>
  </branch>
  <branch name="branch2">
    <leaves>
      <leaf>Leaf 2-1</leaf>
      <leaf>Leaf 2-2</leaf>
    </leaves>
  </branch>
</tree>

Output XML:

<tree>
  <branch name="branch1">
    <leaves>
      <leaf>Leaf 1-1</leaf>
    </leaves>
  </branch>
  <branch name="branch2">
    <leaves>
      <leaf>Leaf 2-1</leaf>
    </leaves>
  </branch>
</tree>
<tree>
  <branch name="branch1">
    <leaves>
      <leaf>Leaf 1-2</leaf>
    </leaves>
  </branch>
  <branch name="branch2">
    <leaves>
      <leaf>Leaf 2-2</leaf>
    </leaves>
  </branch>
</tree>

This approach is clean, maintainable, and aligns with XSLT's template-matching paradigm. The top-down direction makes it easy to control the tree-level attributes first, then drill down to filter the leaves.

内容的提问来源于stack exchange,提问作者Dan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:15:46