使用XSLT在节点计数时转换带有条件的XML

使用XSLT在节点计数时转换带有条件的XML,xml,xslt,Xml,Xslt,我正在尝试从XML文件中删除节点。对于每个XML只使用一个XSLT,我需要根据文档元素的子元素数量在XSLT中做出决策 <root> <branch> <foo>bar</foo> </branch> <root> 酒吧 应该转化为 <branch> </branch> 但是 酒吧 巴兹 进入 也就是说,如果根元素的(唯一)子元素在应用XSLT后可以充当结果

我正在尝试从XML文件中删除节点。对于每个XML只使用一个XSLT,我需要根据文档元素的子元素数量在XSLT中做出决策

<root>
  <branch>
    <foo>bar</foo>
  </branch>
<root>

酒吧
应该转化为

  <branch>
  </branch>

但是


酒吧
巴兹
进入


也就是说,如果根元素的(唯一)子元素在应用XSLT后可以充当结果XML的新文档根,则应该删除根元素。每次都必须删除
节点

有没有办法用单个XSL执行此操作?

试试看

<xsl:template match="@* | node()">
  <xsl:copy>
    <xsl:apply-templates select="@* | node()"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="root[*[2]]">
  <xsl:copy>
    <xsl:apply-templates/>
  </xsl:copy>
</xsl:template>

<xsl:template match="root[* and not(*[2])]">
  <xsl:apply-templates/>
</xsl:template>

<xsl:template match="branch/foo"/>

一种更简单、更短、更通用(无元素名称硬编码)的解决方案

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="/*[not(*[2])]">
  <xsl:apply-templates/>
 </xsl:template>

 <xsl:template match="/*/*/node()"/>
</xsl:stylesheet>
<branch></branch>
<root>
    <branch></branch>
    <branch></branch>
</root>
<t>
    <b></b>
    <b></b>
</t>
<t>
    <b>
        <f>brrr</f>
    </b>
    <b>
        <f>bzzz</f>
    </b>
</t>

当此转换应用于第一个提供的XML文档时(更正为格式正确):


酒吧
生成所需的正确结果

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="/*[not(*[2])]">
  <xsl:apply-templates/>
 </xsl:template>

 <xsl:template match="/*/*/node()"/>
</xsl:stylesheet>
<branch></branch>
<root>
    <branch></branch>
    <branch></branch>
</root>
<t>
    <b></b>
    <b></b>
</t>
<t>
    <b>
        <f>brrr</f>
    </b>
    <b>
        <f>bzzz</f>
    </b>
</t>

在第二个提供的XML文档上应用相同的转换时(同样需要更正格式是否正确):


酒吧
巴兹
再次生成所需的正确输出

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="/*[not(*[2])]">
  <xsl:apply-templates/>
 </xsl:template>

 <xsl:template match="/*/*/node()"/>
</xsl:stylesheet>
<branch></branch>
<root>
    <branch></branch>
    <branch></branch>
</root>
<t>
    <b></b>
    <b></b>
</t>
<t>
    <b>
        <f>brrr</f>
    </b>
    <b>
        <f>bzzz</f>
    </b>
</t>

说明

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="/*[not(*[2])]">
  <xsl:apply-templates/>
 </xsl:template>

 <xsl:template match="/*/*/node()"/>
</xsl:stylesheet>
<branch></branch>
<root>
    <branch></branch>
    <branch></branch>
</root>
<t>
    <b></b>
    <b></b>
</t>
<t>
    <b>
        <f>brrr</f>
    </b>
    <b>
        <f>bzzz</f>
    </b>
</t>
  • 按“原样”复制每个节点

  • 有两个模板覆盖特定节点的标识模板,并以不同的方式处理这些节点

  • 第一个覆盖模板匹配没有第二个元素子元素的top元素。它不复制元素本身,而是处理其子元素

  • 第二个覆盖模板匹配作为顶层元素的一个子元素的任何元素。此模板没有正文,这意味着所有匹配的元素都将被忽略,并且不包括在输出中(换句话说--“已删除”)

  • 注意事项

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
    
     <xsl:template match="node()|@*">
      <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
      </xsl:copy>
     </xsl:template>
    
     <xsl:template match="/*[not(*[2])]">
      <xsl:apply-templates/>
     </xsl:template>
    
     <xsl:template match="/*/*/node()"/>
    </xsl:stylesheet>
    
    <branch></branch>
    
    <root>
        <branch></branch>
        <branch></branch>
    </root>
    
    <t>
        <b></b>
        <b></b>
    </t>
    
    <t>
        <b>
            <f>brrr</f>
        </b>
        <b>
            <f>bzzz</f>
        </b>
    </t>
    
    这种转换可以应用于任何XML文档,而不管其中的元素名称如何,并且仍然可以生成所需的正确结果

    例如,当应用于此XML文档时:

    <t>
        <b>
            <f>brrr</f>
        </b>
        <b>
            <f>bzzz</f>
        </b>
    </t>
    
    
    brrr
    bzzz
    
    生成所需的正确结果

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
    
     <xsl:template match="node()|@*">
      <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
      </xsl:copy>
     </xsl:template>
    
     <xsl:template match="/*[not(*[2])]">
      <xsl:apply-templates/>
     </xsl:template>
    
     <xsl:template match="/*/*/node()"/>
    </xsl:stylesheet>
    
    <branch></branch>
    
    <root>
        <branch></branch>
        <branch></branch>
    </root>
    
    <t>
        <b></b>
        <b></b>
    </t>
    
    <t>
        <b>
            <f>brrr</f>
        </b>
        <b>
            <f>bzzz</f>
        </b>
    </t>
    
    
    
    将此结果与当前公认答案产生的结果进行对比

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
    
     <xsl:template match="node()|@*">
      <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
      </xsl:copy>
     </xsl:template>
    
     <xsl:template match="/*[not(*[2])]">
      <xsl:apply-templates/>
     </xsl:template>
    
     <xsl:template match="/*/*/node()"/>
    </xsl:stylesheet>
    
    <branch></branch>
    
    <root>
        <branch></branch>
        <branch></branch>
    </root>
    
    <t>
        <b></b>
        <b></b>
    </t>
    
    <t>
        <b>
            <f>brrr</f>
        </b>
        <b>
            <f>bzzz</f>
        </b>
    </t>
    
    
    brrr
    bzzz
    
    +1谢谢,似乎在我的沙箱中工作。我现在正在学习XSLT:像[*而不是…]这样的正则表达式是否需要XSLT2.0?用于字符串匹配的正则表达式仅在XSLT和XPath2.0中受支持。但是,我只使用了XSLT1.0元素匹配模式,因为
    match=“root[*[2]]”
    只是
    match=“root[child::*[2]]”
    的缩写形式,意思是将
    root
    元素与至少两个任意名称的子元素进行匹配。