仅保留列入白名单的元素和/或属性

时间:2019-01-29 11:42:40

标签: xml xslt xslt-1.0

我有一个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

例如,我可以通过使用简单的 if-match-do-nothing 来为此编写一个简单的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来陈述我想要的东西,我发现两个问题部分地回答了这个问题。 One question为节点引入了白名单,other question为属性引入了白名单。如何在单个白名单中优雅地执行此操作,或者有更好的方法?可以通过以下形式的白名单来完成此操作:

<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>

相关问题:

2 个答案:

答案 0 :(得分:2)

这会为您做到吗?有一个与var myCtx = {table: 'Product', alias: 'ProductView'}; evalInContext(' table == "" ', myCtx); //#false evalInContext(' alias == "ProductView" ', myCtx); //#true 元素的子元素匹配的模板,然后检查白名单文档以查看是否复制该节点,如果要复制,还应复制哪些属性

grid = np.array([
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])

start = (12,0)
goal = (0,10)

答案 1 :(得分:2)

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

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>

否则它可能会变得非常复杂:

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

  • 这不是那么容易-尤其是。在XSLT 1.0中-查看节点是否在树的层次结构中出现在相同的位置(即,指向该节点的 path 与该节点中的节点的路径相同)白名单)。

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

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