通过XSLT从XML中删除空标记
我有一个如下模式的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 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.0boolean()
函数应用于标记内容如果内容是长度为零的字符串,其结果将为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感谢您的快速回复,我已经找到了所需的解决方案