只保留白色列出的元素和/或属性



我有一个XML文件,其中有很多节点,每个节点都有大量的属性。为了简单起见,让我们假设XML如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<root>
<header />
<group>
<node1 attr1="x" attr2="y" attr3="z" />
<node2 attr4="x" attr5="y" attr6="z" />
<node3 attr7="x" attr8="y" attr9="z" />
<node1 attr1="x" attr2="y" attr3="z" />
</group>
</root>

我想通过消除属性和节点来减少/root/group/的内容,从而将此XML简化为较小的版本。

  • 应删除所有名为node3的节点
  • 名称为node1的节点应仅具有属性attr1
  • 名称为node2的节点应仅具有属性attr5attr6

我可以通过使用简单的来为此编写一个简单的XSLT,如果匹配什么都不做,例如

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:template match="/root/group/node3" />
<xsl:template match="/root/group/node1/@attr2" />
<xsl:template match="/root/group/node1/@attr3" />
<xsl:template match="/root/group/node2/@attr4" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

然而,这不符合我的需要。上面陈述了我不想要的东西,但我想通过使用白名单来陈述我想要的东西。我发现的两个问题部分回答了这个问题。一个问题介绍了节点的白名单,另一个问题则介绍了属性的白名单。我如何在一个白名单中优雅地做到这一点,或者有更好的方法吗?这可以在以下形式的白名单中完成吗:

<whitelist>
<node1 attr1="" />
<node2 attr5="" attr6="" />
</whitelist>

备注:我只能使用XSLT-1.0

预期输出:

<?xml version="1.0" encoding="UTF-8"?>
<root>
<header />
<group>
<node1 attr1="x" />
<node2 attr5="y" attr6="z" />
<node1 attr1="x" />
</group>
</root>

相关问题:

  • XSLT-如何从XML中只保留所需元素
  • XSL:复制与白名单匹配的属性

这对你有用吗?有一个与group元素的子元素匹配的单个模板,然后检查白名单文档,看看是否复制该节点,如果是,还应该复制哪些属性

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns="ns" version="1.0">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<ns:WhiteList>
<node>
<name>node1</name>
<attr>attr1</attr>
</node>
<node>
<name>node2</name>
<attr>attr5</attr>
<attr>attr6</attr>
</node>
</ns:WhiteList>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="group/*">
<xsl:variable name="node" select="document('')//ns:WhiteList/node[name = name(current())]" />
<xsl:if test="$node">
<xsl:copy>
<xsl:apply-templates select="@*[name() = $node/attr]|node()" />
</xsl:copy>
</xsl:if>
</xsl:template>
</xsl:stylesheet>

简单的方法是使样式表本身成为"白名单":

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="group">
<xsl:copy>
<xsl:apply-templates select="node1 | node2"/>
</xsl:copy>
</xsl:template>
<xsl:template match="node1">
<xsl:copy>
<xsl:apply-templates select="@attr1"/>
</xsl:copy>
</xsl:template>
<xsl:template match="node2">
<xsl:copy>
<xsl:apply-templates select="@attr5 | @attr6"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

否则会变得非常复杂:

  • 测试一个节点是否按其名称出现在给定的白名单中相对容易(就像他们在您链接的其他问题上所做的那样);

  • 查看节点是否出现在树的层次结构中的同一位置并不容易,尤其是在XSLT1.0中(即节点的路径与白名单中节点的路径相同)。

如果只通过名称进行测试就足够了,那么您可以执行以下操作:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="http://example.com/my"
exclude-result-prefixes="my">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<my:whitelist>
<root>
<header/>
<group>
<node1 attr1=""/>
<node2 attr5="" attr6=""/>
</group>
</root>
</my:whitelist>
<xsl:variable name="whitelist" select="document('')/xsl:stylesheet/my:whitelist"/>
<xsl:template match="*">
<xsl:if test="$whitelist//*[name() = name(current())]">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:if>
</xsl:template>
<xsl:template match="@*">
<xsl:if test="$whitelist//@*[name() = name(current())]">
<xsl:copy/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>

但是你当然可以简化白名单的结构,因为它被完全忽略了。


有关如何使用由路径组成的白名单来完成此操作的示例,请参阅:https://stackoverflow.com/a/30276667/3016153

相关内容

  • 没有找到相关文章

最新更新