Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xslt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
通过XSLT从XML中删除空标记_Xslt - Fatal编程技术网

通过XSLT从XML中删除空标记

通过XSLT从XML中删除空标记,xslt,Xslt,我有一个如下模式的xml <?xml version="1.0" encoding="UTF-8"?> <Person> <FirstName>Ahmed</FirstName> <MiddleName/> <LastName>Aboulnaga</LastName> <CompanyInfo> <CompanyName&g

我有一个如下模式的xml

<?xml version="1.0" encoding="UTF-8"?>
    <Person>
      <FirstName>Ahmed</FirstName>
      <MiddleName/>
      <LastName>Aboulnaga</LastName>
      <CompanyInfo>
        <CompanyName>IPN Web</CompanyName>
        <Title/>
    <Role></Role>
        <Department>
    </Department>
      </CompanyInfo>
    </Person>

艾哈迈德
阿布纳加
IPN网络
我在尝试删除空标记时使用了以下xslt(来自论坛)


使用的xslt成功地删除了如下标记

<Title/>
    <Role></Role>

…但在两行上有空标记时失败,例如:

<Department>
    </Department>

这有什么解决办法吗?


<xsl:template match="@*|node()">
  <xsl:if test="normalize-space(.) != '' or ./@* != ''">
    <xsl:copy>
       <xsl:copy-of select = "@*"/>
       <xsl:apply-templates/>
    </xsl:copy>
  </xsl:if>
</xsl:template>

您的问题没有明确说明。空是什么意思?
这里是空的吗

<outer><inner/></outer>

无论如何,这里有一种方法可能适合您的要求:

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


注意:您可能需要调整优先级以满足您的需要。

此转换根本不需要任何条件XSLT指令,也不使用明确的优先级:

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

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

 <xsl:template match=
    "*[not(@*|*|comment()|processing-instruction()) 
     and normalize-space()=''
      ]"/>
</xsl:stylesheet>

应用于提供的XML文档时

<Person>
    <FirstName>Ahmed</FirstName>
    <MiddleName/>
    <LastName>Aboulnaga</LastName>
    <CompanyInfo>
        <CompanyName>IPN Web</CompanyName>
        <Title/>
        <Role></Role>
        <Department>
        </Department>
    </CompanyInfo>
</Person>
<Person>
   <FirstName>Ahmed</FirstName>
   <LastName>Aboulnaga</LastName>
   <CompanyInfo>
      <CompanyName>IPN Web</CompanyName>
   </CompanyInfo>
</Person>

艾哈迈德
阿布纳加
IPN网络
它生成所需的正确结果

<Person>
    <FirstName>Ahmed</FirstName>
    <MiddleName/>
    <LastName>Aboulnaga</LastName>
    <CompanyInfo>
        <CompanyName>IPN Web</CompanyName>
        <Title/>
        <Role></Role>
        <Department>
        </Department>
    </CompanyInfo>
</Person>
<Person>
   <FirstName>Ahmed</FirstName>
   <LastName>Aboulnaga</LastName>
   <CompanyInfo>
      <CompanyName>IPN Web</CompanyName>
   </CompanyInfo>
</Person>

艾哈迈德
阿布纳加
IPN网络
(……)这有什么解决办法吗

<xsl:template match="@*|node()">
  <xsl:if test="normalize-space(.) != '' or ./@* != ''">
    <xsl:copy>
       <xsl:copy-of select = "@*"/>
       <xsl:apply-templates/>
    </xsl:copy>
  </xsl:if>
</xsl:template>
两行上的标记不是空标记。它是一个包含空格的标记(如新行和可能的某种空白字符)。XPath 1.0函数
normalize-space()
允许您通过剥离不需要的新行来规范标记的内容

将函数应用于标记内容后,可以检查空字符串。实现这一点的一个好方法是将XPath 1.0
boolean()
函数应用于标记内容如果内容是长度为零的字符串,其结果将为false

最后,您可以嵌入稍微改变身份转换的所有内容。您不需要
xsl:if
说明或任何其他模板

最终的变换将如下所示:

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

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

</xsl:stylesheet>


附加说明


您的
xsl:if
指令当前也在检查空属性。通过这种方式您实际上也在删除具有空属性的非empy标记。这听起来不像是“删除空标签”。所以要小心,否则你的问题会遗漏一些细节,或者你使用的是不安全的代码。

根据我在网上的发现,这是最正确的答案:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml"/>
    <xsl:template match="/">
        <xsl:apply-templates select="*"/>
    </xsl:template>
    <xsl:template match="*">
            <xsl:if test=".!=''">
                <xsl:copy>
                  <xsl:copy-of select="@*"/>
                  <xsl:apply-templates/>
                </xsl:copy>
            </xsl:if>
    </xsl:template>
</xsl:stylesheet>

您可以使用以下xslt删除空标记/属性:

<?xml version="1.0" encoding="UTF-8"?>
<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="node()">
        <xsl:if test="normalize-space(string(.)) != ''
                        or count(@*[normalize-space(string(.)) != '']) > 0
                        or count(descendant::*[normalize-space(string(.)) != '']) > 0
                        or count(descendant::*/@*[normalize-space(string(.)) != '']) > 0">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
        </xsl:if>
    </xsl:template>

    <xsl:template match="@*">
        <xsl:if test="normalize-space(string(.)) != ''">
            <xsl:copy>
                <xsl:apply-templates select="@*" />
            </xsl:copy>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>


问得好,+1。请参阅我的答案,以获得一个完整、简短、简单的解决方案,该解决方案不使用任何条件指令或明确的优先级,并且基于最基本、最强大的XSLT设计模式——覆盖标识规则。请小心使用术语。您的
department
元素不是空的,因为空白在XML元素中很重要。你可以说它只包含空格,但你不能说它是空的。问题和努力+1。请参阅我的答案,了解实现所需结果所需的XPath 1.0函数,以及如何仅使用一个模板即可实现这一点。下面提供的解决方案满足您的需求。我想知道你为什么没有接受/投票其中的任何一个。请注意术语:标记标记元素的开始和结束。标签不能为空。您希望删除的是空元素,而不是标记。@鲍勃·瓦尔:为什么要删除具有一个或多个属性(甚至所有属性都有值“”)的元素?@鲍勃·瓦尔:您的代码删除了一个类似
的元素,所以您的意思是删除具有空属性的元素。这是因为我复制了发问者使用的代码,并假设他们需要这些代码。嘿:)我有一个简短的问题。如果节点
也为空,则输出XML将具有
名、姓和空标记
,这是因为其所有子元素都是空标记。这对于要求来说已经足够公平了。但是,如果我想摆脱
,因为它的子节点是空的,并且插入
的父节点(如果(假设)
是它的父节点的唯一子节点,而现在整个层次结构是空的),那么需要做什么呢。提前感谢。为了方便起见,我们可以假设给定的XML只是原始XML的一部分,并且像“ROW_ID”这样的强制节点将始终填充。因此,输出XML不会为空。我已经想出了一个代码,可以忽略一个没有包含数据的子元素的节点。但是我在递归性方面遇到了一些问题,我指的是空节点的父节点等等。@InfantPro'Aravind',只需将
CompanyName[not(node)或not(*//node())]
添加到上一个模板的匹配模式中即可。@dimitre novatchev这适用于给定的场景,但如果我想像中那样递归地执行该操作,该怎么办,考虑下面的例子->代码>…..
运行转换后,仅移除最里面的标记,即:;并将外壳移除;但我想把整个block@dimitre-novatchev感谢您的快速回复,我已经找到了所需的解决方案