Xml 基于属性删除空元素和子体

Xml 基于属性删除空元素和子体,xml,xslt,Xml,Xslt,我正在尝试创建一个XSLT,该XSLT将删除满足以下任一条件的所有元素和任何元素的所有后代: 元素为空(无文本,仅空白)并且没有属性 元素为空,并且有一个或多个属性都为空(否 文本,仅限空白) 换句话说:应该保留的元素只有不为空的和为空且至少有一个属性为非空的元素 此外,XSLT必须具有足够的通用性/动态性,以处理给定XML输入的任何XML,并根据上述期望生成结果 我目前正在使用以下XSLT: <xsl:stylesheet xmlns:xsl="http://www.w3.org/199

我正在尝试创建一个XSLT,该XSLT将删除满足以下任一条件的所有元素和任何元素的所有后代:

  • 元素为空(无文本,仅空白)并且没有属性
  • 元素为空,并且有一个或多个属性都为空(否 文本,仅限空白)
  • 换句话说:应该保留的元素只有不为空的为空且至少有一个属性为非空的元素

    此外,XSLT必须具有足够的通用性/动态性,以处理给定XML输入的任何XML,并根据上述期望生成结果

    我目前正在使用以下XSLT:

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        version="1.0">
        <xsl:output method="xml" omit-xml-declaration="no" indent="no" />
        <xsl:strip-space elements="*" />
    
        <xsl:template match="/">
            <xsl:apply-templates select="*" />
        </xsl:template>
    
        <xsl:template match="*">
            <xsl:if test="(normalize-space(.)) or (normalize-space(.//@*))">
                <xsl:copy>
                    <xsl:element name="name()">
                        <xsl:copy-of select="@*" />
                        <xsl:apply-templates />
                    </xsl:element>
                </xsl:copy>
            </xsl:if>
        </xsl:template>
    
    </xsl:stylesheet>
    
    也从输出中过滤掉了

    我已经为这个实现尝试了许多变体,这是我最接近达到预期结果的一次



    我希望我已经清楚地提供了足够的细节来描述我正在努力实现的目标。如有必要,我将根据要求提供更多详细信息。

    这是一个非常好且清晰的问题,有明确的例子说明您的目标,很高兴看到您自己已经尝试过了

    您的代码很少发生以下情况: -显示的输出与运行样式表时将获得的输出不匹配,因为: -您正在复制每个元素,方法是首先浅层复制它(
    xsl:copy
    ),然后手动复制(
    xsl:element
    with
    name()
    ) -在我编辑样式表之前,它是无效的,也就是说,
    name=“name()”
    是非法的,它应该是
    name=“{name()}”
    。 -您正在对所有底层节点的值使用
    xsl:if
    normalize space
    进行测试,这是它们所有文本内容的串联。这不是您想要的,您还应该测试子节点,或者只测试文本节点(见下文) -您已经使用
    xsl:strip space
    规范化了空间,除非您真的还想忽略纯空白属性(不在REQ中),否则应该使用它,否则就没有必要了

    这是您提供的输入XML的实际输出,显然也不是您想要的:

    <?xml version="1.0" encoding="UTF-8"?>
    <Parents>
       <Parents>
          <Parent>
             <Parent test="A"/>
          </Parent>
          <Parent>
             <Parent>Parent 1</Parent>
          </Parent>
          <Parent>
             <Parent>
                <Child>
                   <Child test="A"/>
                </Child>
             </Parent>
          </Parent>
          <Parent>
             <Parent>
                <Child>
                   <Child>Child 1</Child>
                </Child>
             </Parent>
          </Parent>
          <Parent>
             <Parent>
                <Child>
                   <Child>
                      <GrandChild>
                         <GrandChild test="A"/>
                      </GrandChild>
                   </Child>
                </Child>
             </Parent>
          </Parent>
          <Parent>
             <Parent>
                <Child>
                   <Child>
                      <GrandChild>
                         <GrandChild>GrandChild 1</GrandChild>
                      </GrandChild>
                   </Child>
                </Child>
             </Parent>
          </Parent>
          <Parent>
             <Parent>
                <Child>
                   <Child>
                      <GrandChild>
                         <GrandChild>
                            <GreatGrandChild>
                               <GreatGrandChild test="A"/>
                            </GreatGrandChild>
                         </GrandChild>
                      </GrandChild>
                   </Child>
                </Child>
             </Parent>
          </Parent>
          <Parent>
             <Parent>
                <Child>
                   <Child>
                      <GrandChild>
                         <GrandChild>
                            <GreatGrandChild>
                               <GreatGrandChild>GreatGrandChild 1</GreatGrandChild>
                            </GreatGrandChild>
                         </GrandChild>
                      </GrandChild>
                   </Child>
                </Child>
             </Parent>
          </Parent>
       </Parents>
    </Parents>
    
    样式表复制所有内容(所有类型的节点,还有注释和处理指令),这是第一个模板。第二个模板故意为空,只是删除了适合其过滤器的所有内容。这是可行的,因为在XSLT中,更具体的模板比不太具体的模板具有更高的优先级

    当前的输出如下所示,与您的输出不完全匹配,但与您的描述符合我的理解方式:

    <?xml version="1.0" encoding="UTF-8"?>
    <Parents>
       <Parent test="A"/>
       <Parent>Parent 1</Parent>
       <Parent/>
       <Parent>
          <Child test="A"/>
       </Parent>
       <Parent>
          <Child>Child 1</Child>
       </Parent>
       <Parent>
          <Child/>
       </Parent>
       <Parent>
          <Child>
             <GrandChild test="A"/>
          </Child>
       </Parent>
       <Parent>
          <Child>
             <GrandChild>GrandChild 1</GrandChild>
          </Child>
       </Parent>
       <Parent>
          <Child>
             <GrandChild/>
          </Child>
       </Parent>
       <Parent>
          <Child>
             <GrandChild>
                <GreatGrandChild test="A"/>
             </GrandChild>
          </Child>
       </Parent>
       <Parent>
          <Child>
             <GrandChild>
                <GreatGrandChild>GreatGrandChild 1</GreatGrandChild>
             </GrandChild>
          </Child>
       </Parent>
    </Parents>
    
    
    父1
    儿童1
    孙女1
    曾孙1
    
    更新:通过重新阅读您的需求,您确实提到了后代。回想起来,我认为你的意思是:

    <xsl:template match="*[not(.//text())][normalize-space(.//@*) = '']" />
    
    • 如果元素的任何子元素包含非空白文本,请保留该元素
    • 如果元素的任何子元素包含非空白属性值,则保留该元素
    • 删除其余部分
    如果这是正确的,您可以通过检查不存在的子代文本节点并合并所有子代属性节点来实现。将上面的过滤管路更换为以下部件:

    <xsl:template match="*[not(.//text())][normalize-space(.//@*) = '']" />
    
    
    

    这将为您提供与您的预期输出完全相同的输出(并且与您的尝试已经显示的结果更接近)。

    哇,这正是我所期待的!我使用在线XSLT测试工具确认了您在最终更新中提出的解决方案按预期工作,尽管由于某些原因,它在使用Xalan 2.7.1处理器运行Eclipse进行转换时没有产生预期的输出(这正是我真正需要确认的地方)。不幸的是,昨天我的要求在最后一刻发生了变化,我不得不朝着一个完全不同的方向前进。不管怎样,你的解决方案奏效了,所以我将此标记为已解决。谢谢亚伯@尤金。谢谢,如果你喜欢的话,你可以考虑回答这个问题。(有点像StackOverflow的习惯)。如果Xalan没有产生正确的结果,这可能是处理器中的一个bug,但是正如您所说的,您的需求发生了变化,所以这个问题没有意义。无论如何,很高兴能帮上忙!我喜欢你的回答——它快速、清晰、详细。诚实超出了我的期望。不幸的是,在我达到15岁之前,我无法提高投票率:(.我想如果可能的话,我必须稍后回来提高投票率;)。再次感谢!
    <?xml version="1.0" encoding="UTF-8"?>
    <Parents>
       <Parents>
          <Parent>
             <Parent test="A"/>
          </Parent>
          <Parent>
             <Parent>Parent 1</Parent>
          </Parent>
          <Parent>
             <Parent>
                <Child>
                   <Child test="A"/>
                </Child>
             </Parent>
          </Parent>
          <Parent>
             <Parent>
                <Child>
                   <Child>Child 1</Child>
                </Child>
             </Parent>
          </Parent>
          <Parent>
             <Parent>
                <Child>
                   <Child>
                      <GrandChild>
                         <GrandChild test="A"/>
                      </GrandChild>
                   </Child>
                </Child>
             </Parent>
          </Parent>
          <Parent>
             <Parent>
                <Child>
                   <Child>
                      <GrandChild>
                         <GrandChild>GrandChild 1</GrandChild>
                      </GrandChild>
                   </Child>
                </Child>
             </Parent>
          </Parent>
          <Parent>
             <Parent>
                <Child>
                   <Child>
                      <GrandChild>
                         <GrandChild>
                            <GreatGrandChild>
                               <GreatGrandChild test="A"/>
                            </GreatGrandChild>
                         </GrandChild>
                      </GrandChild>
                   </Child>
                </Child>
             </Parent>
          </Parent>
          <Parent>
             <Parent>
                <Child>
                   <Child>
                      <GrandChild>
                         <GrandChild>
                            <GreatGrandChild>
                               <GreatGrandChild>GreatGrandChild 1</GreatGrandChild>
                            </GreatGrandChild>
                         </GrandChild>
                      </GrandChild>
                   </Child>
                </Child>
             </Parent>
          </Parent>
       </Parents>
    </Parents>
    
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        version="1.0">
        <xsl:output method="xml" omit-xml-declaration="no" indent="yes" />
        <xsl:strip-space elements="*" />
    
        <xsl:template match="node() | @*">
            <xsl:copy>
                <xsl:apply-templates select="node() | @*" />
            </xsl:copy>
        </xsl:template>
    
        <!-- remove empty elements, or empty elements with empty attribs -->
        <xsl:template match="*[not(*)][not(text())][normalize-space(@*) = '']" />
    
    </xsl:stylesheet>
    
    <?xml version="1.0" encoding="UTF-8"?>
    <Parents>
       <Parent test="A"/>
       <Parent>Parent 1</Parent>
       <Parent/>
       <Parent>
          <Child test="A"/>
       </Parent>
       <Parent>
          <Child>Child 1</Child>
       </Parent>
       <Parent>
          <Child/>
       </Parent>
       <Parent>
          <Child>
             <GrandChild test="A"/>
          </Child>
       </Parent>
       <Parent>
          <Child>
             <GrandChild>GrandChild 1</GrandChild>
          </Child>
       </Parent>
       <Parent>
          <Child>
             <GrandChild/>
          </Child>
       </Parent>
       <Parent>
          <Child>
             <GrandChild>
                <GreatGrandChild test="A"/>
             </GrandChild>
          </Child>
       </Parent>
       <Parent>
          <Child>
             <GrandChild>
                <GreatGrandChild>GreatGrandChild 1</GreatGrandChild>
             </GrandChild>
          </Child>
       </Parent>
    </Parents>
    
    <xsl:template match="*[not(.//text())][normalize-space(.//@*) = '']" />