过滤掉不需要的XML子节点,并使用XSLT或XPATH过滤父节点

时间:2019-01-23 21:02:49

标签: xml xslt

我试图为一个一次性项目选择XLST完全迷失了(使用专有的脚本语言来解析下载的Salesforce模式信息以实现表间关系,该脚本语言基本上只给了我XPATH,XSLT和while循环- -直到今天我还没有听说过XSLT ...对于我的过滤器需求的后半部分,它看起来很有希望)

我输入的XML看起来像这样:

<result>
    <custom>True</custom>
    <createable>False</createable>
    <fields>
        <createdBy>Joe</createdBy>
        <name>field1</name>
        <referenceTo>otherPlaceXYZ</referenceTo>
        <type>reference</type>
    </fields>
    <fields>
        <createdBy>Joe</createdBy>
        <name>field2</name>
    </fields>
    <fields>
        <createdBy>Joe</createdBy>
        <name>field3</name>
        <referenceTo>otherPlaceABC</referenceTo>
        <type>reference</type>
    </fields>
    <name>CoolName</name>
    <label>A label</label>
    <searchable>False</searchable>
</result>

我想做两种类型的过滤器:

  1. 丢弃没有<fields>...</fields>子节点的所有<type>reference</type>节点
  2. 在剩余的数据中,丢弃不是<result>...</result><fields>...</fields><name>...</name>的{​​{1}}的所有子级,并丢弃不是<label>...</label><fields>...</fields>的{​​{1}} (尽管我不反对<name>...</name>,因为这样做会使代码更简单) 。请注意,我实际上有5或6个字段要保留在“字段”之内(在文件中不超过几十个),但在示例中要保持简短简短。同样,有数十个我实际上并不关心的“结果”子项。

我希望我的输出数据看起来像这样:

<referenceTo>...</referenceTo>

我一直在http://www.utilities-online.info/xsltransformation/玩耍,但是很困。与“相同的XML文件,只有较小的文件”相比,关于XSLT的文档似乎主要针对的是进行更复杂的数据转换,因此,我努力寻找最简单的方法来完成此工作。

有指针吗?

感谢deleting the parent node if child node is not present in xml using xslt,我已经做到了这一点,但我不确定我是否出于我对输出的最终渴望而树了正确的树。

<type>...</type>

2 个答案:

答案 0 :(得分:1)

您可以通过停用其中一个内置模板并创建要复制的节点的白名单来做到这一点:

要停用的内置模板描述为here at O'Reilly

  

元素和文档节点的内置模板规则

     

此模板处理文档节点及其任何子节点。即使没有为给定元素声明模板,此处理也可以确保递归处理将继续:

<xsl:template match="*|/">
   <xsl:apply-templates/>
</xsl:template>

因此您的XSLT-1.0样式表应如下所示:

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

    <!-- Deactivate built-in template for elements -->
    <xsl:template match="*" />

    <!-- Apply the white list of nodes to copy -->
    <xsl:template match="/ | fields[type/text() = 'reference'] | result | result/name | result/label | fields/name | fields/referenceTo | @* | text()">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*" />
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

例如,result/name仅选择name子级的result

输出为:

<?xml version="1.0"?>
<result>
    <fields>
        <name>field1</name>
        <referenceTo>otherPlaceXYZ</referenceTo>
    </fields>
    <fields>
        <name>field3</name>
        <referenceTo>otherPlaceABC</referenceTo>
    </fields>
    <name>CoolName</name>
    <label>A label</label>
</result>

答案 1 :(得分:1)

我的偏好是使用xsl:apply-templates进行过滤:

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="/result">
    <xsl:copy>
        <xsl:apply-templates select="fields[type='reference']|name|label" />
    </xsl:copy>
</xsl:template>

<xsl:template match="fields">
    <xsl:copy>
        <xsl:apply-templates select="name|referenceTo" />
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>