【问题标题】:Remove parent node when child node is empty XSLT子节点为空时删除父节点 XSLT
【发布时间】:2022-09-23 23:48:28
【问题描述】:

我有一个如下的 XML:

<Main>
    <rFs>
        <rF>
            <iT>T</iT>
            <ref>F1</ref>
            <recs>
                <rec>
                    <iT>T</iT>
                    <ref>T0</ref>
                    <cT Code=\"R\" Des=\"Regular\">R</cT>
                    <fT Code=\"N\" Description=\"National\">N</fT>
                    <st Code=\"D\" Description=\"Dock\">D</st>
                </rec>
                <rec>
                    <iT>T</iT>
                    <ref>T0</ref>
                    <cT Code=\"R\" Description=\"Regular\">R</cT>
                    <fT Code=\"Q\" Description=\"Mad\">Q</fT>
                </rec>
            </recs>
        </rF>
        <rF>
            <iT>T</iT>
            <ref>F2</ref>
            <recs>
                <rec>
                    <iT>T</iT>
                    <ref>T1</ref>
                    <cT Code=\"S\" Des=\"Regular\">R</cT>
                    <fT Code=\"N\" Description=\"Inter\">I</fT>
                </rec>
                <rec>
                    <iT>T</iT>
                    <ref>T1</ref>
                    <cT Code=\"S\" Description=\"Time\">R</cT>
                    <fT Code=\"Q\" Description=\"Mad\">Q</fT>
                </rec>
            </recs>
        </rF>
    </rFs>
</Main>

根据要求,已经有一个 XSLT。 XSLT 如下:

<xsl:template match=\"Main\">
    <rFs>
        <xsl:for-each select=\"rFs/rF[iT = \'T\']\">
            <rF>
                <xsl:attribute name=\"id\">
                    <xsl:value-of select=\"concat(ref,\'_\',\'fam\')\"/>
                </xsl:attribute>
                <recs>
                    <xsl:for-each-group select=\"recs/rec\" group-by=\"ref\">
                        <xsl:for-each select=\"current-group()\">
                            <rec>
                                <xsl:attribute name=\"id\">
                                    <xsl:value-of select=\"ref\"/>
                                </xsl:attribute>
                                <st>
                                    <xsl:value-of select=\"st/@Code\"/>
                                </st>
                            </rec>
                        </xsl:for-each>
                    </xsl:for-each-group>
                </recs>
            </rF>
        </xsl:for-each>
    </rFs>
</xsl:template>

上面的 XSLT 给出了以下 XML 作为输出 -

<rFs>
    <rF id=\"F1_fam\">
        <recs>
            <rec id=\"T0\">
                <st>D</st>
            </rec>
            <rec id=\"T0\">
                <st/>
            </rec>
        </recs>
    </rF>
    <rF id=\"F2_fam\">
        <recs>
            <rec id=\"T1\">
                <st/>
            </rec>
            <rec id=\"T1\">
                <st/>
            </rec>
        </recs>
    </rF>
</rFs>

现在我必须在上面的XSLT 中进行更新。 我的要求是:

    1. 删除&lt;rec&gt; 其中&lt;st&gt; 为空
      1. 如果&lt;rf&gt;下的所有&lt;rec&gt;都将&lt;st&gt;设为null,则删除整个&lt;rf&gt;

上述要求的实现应生成最终 XML:

<rFs>
    <rF id=\"F1_fam\">
        <recs>
            <rec id=\"T0\">
                <st>D</st>
            </rec>
        </recs>
    </rF>
</rFs>

我已经阅读了很多关于相同的帖子,但似乎没有任何效果。

标签: xslt


【解决方案1】:

这是在初始结果的第二阶段处理中使用 xsl:where-populated 的 XSLT 3 方式:

<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:template match="Main">
    <xsl:variable name="first-transformation-result">
        <rFs>
            <xsl:for-each select="rFs/rF[iT = 'T']">
            <rF>
                <xsl:attribute name="id"><xsl:value-of select="concat(ref,'_','fam')"/></xsl:attribute>
                <recs>
                    <xsl:for-each-group select="recs/rec" group-by="ref">
                    <xsl:for-each select="current-group()">
                        <rec>
                            <xsl:attribute name="id"><xsl:value-of select="ref"/></xsl:attribute>
                            <st><xsl:value-of select="st/@Code"/></st>
                        </rec>
                    </xsl:for-each>
                    </xsl:for-each-group>
                </recs>
            </rF>
            </xsl:for-each>
        </rFs>
      </xsl:variable>
      <xsl:apply-templates select="$first-transformation-result/node()"/>
  </xsl:template>

  <xsl:mode on-no-match="shallow-copy"/>
  
  <xsl:output indent="yes"/>

  <xsl:template match="*">
    <xsl:where-populated>
      <xsl:next-match/>
    </xsl:where-populated>
  </xsl:template>
  
</xsl:stylesheet>

或者甚至可能

<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:template match="Main">
        <rFs>
            <xsl:for-each select="rFs/rF[iT = 'T']">
            <rF>
                <xsl:attribute name="id"><xsl:value-of select="concat(ref,'_','fam')"/></xsl:attribute>
                <recs>
                    <xsl:for-each-group select="recs/rec" group-by="ref">
                    <xsl:for-each select="current-group()">
                        <rec>
                            <xsl:attribute name="id"><xsl:value-of select="ref"/></xsl:attribute>
                            <st><xsl:value-of select="st/@Code"/></st>
                        </rec>
                    </xsl:for-each>
                    </xsl:for-each-group>
                </recs>
            </rF>
            </xsl:for-each>
        </rFs>
  </xsl:template>
  
  <xsl:template match="Main" priority="5">
    <xsl:variable name="first-transformation-result">
      <xsl:next-match/>
    </xsl:variable>
    <xsl:apply-templates select="$first-transformation-result/node()"/>
  </xsl:template>

  <xsl:mode on-no-match="shallow-copy"/>
  
  <xsl:output indent="yes"/>

  <xsl:template match="*">
    <xsl:where-populated>
      <xsl:next-match/>
    </xsl:where-populated>
  </xsl:template>
  
</xsl:stylesheet>

重用现有模板不变。

【讨论】:

  • 以前的 XSLT 在 2.0 中
  • @user13583928,您使用哪种 XSLT 处理器?大多数 XSLT 2 处理器(如 Saxon)已更新为支持 XSLT 3,即 Saxon 已从 XSLT 2(实施到 Saxon 9.7)转移到自 9.8 起实施的 XSLT 3。当前版本是 11。
【解决方案2】:

简单地说:

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:template match="/Main">
    <rFs>
        <xsl:for-each select="rFs/rF[iT='T'][descendant::st/text()]">
            <rF id="{ref}_fam">
                <recs>
                    <xsl:for-each select="recs/rec[st/text()]">
                        <xsl:sort select="ref"/>
                        <rec id="{ref}">
                            <st>
                                <xsl:value-of select="st/@Code"/>
                            </st>
                        </rec>
                    </xsl:for-each>
                </recs>
            </rF>
        </xsl:for-each>
    </rFs>
</xsl:template>

</xsl:stylesheet>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多