Java 使用给定的xpath列表在xml中只保留所需的元素

Java 使用给定的xpath列表在xml中只保留所需的元素,java,xml,dom,xslt,xpath,Java,Xml,Dom,Xslt,Xpath,我有一些复杂的xml结构。有时,我只想让元素与xpath条目的运行时列表相匹配 示例xml 在上面的xpath中,如果您观察到我们在Department中有Department和Name,那么在这种情况下,我可以忽略Department //Employee/Address //Employee/Department/name 我想要的结果xml如下 <Employee> <Address> <addressLine1>Dummy L

我有一些复杂的xml结构。有时,我只想让元素与xpath条目的运行时列表相匹配

示例xml

在上面的xpath中,如果您观察到我们在Department中有Department和Name,那么在这种情况下,我可以忽略Department

//Employee/Address
//Employee/Department/name
我想要的结果xml如下

<Employee>
    <Address>
        <addressLine1>Dummy Line 1</addressLine1>
        <zip>535270</zip>
    </Address>
    <Department>
        <name>development</name>
    </Department
</Employee>

我意识到我可以通过xslt实现这一点。所以我想要xslt来满足这种通用需求。我当前的代码也是用java编写的。java中有更好的替代方案吗?

我不得不承认,我并不完全理解您的需求,但我看到的是:

您有一组XPath 如果将这些XPath语句应用于输入文档,您似乎希望得到它们的并集 与XPath联合表达式一样删除重复项 某些元素即使不在XPath语句列表中,也可能会出现。 我最初的反应是:使用xsl:evaluate,但考虑到您正在生成所有XPath表达式,这可能不会给出您想要的结果。此外,它还需要一个XSLT 3.0处理器

使用XSLT 2.0,您可以执行以下操作:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs" 
    version="2.0">

    <xsl:strip-space elements="*" />

    <xsl:output indent="yes" />

    <xsl:variable name="patterns" as="xs:string*">
        <xsl:sequence select="(
            'foo/bar',
            'foo/test',
            'foo/bar/zed')" />
    </xsl:variable>

    <xsl:template match="node()[true() = (
        for $p in $patterns 
        return ends-with(
            string-join(current()/ancestor-or-self::*/name(), 
            '/'), $p))]">
        <xsl:copy>
            <xsl:apply-templates />
        </xsl:copy>
    </xsl:template>

    <xsl:template match="text()" />

</xsl:stylesheet>
这只是为了让你开始,而不是作为一个全面的解决方案。它匹配产品//QName/QName的XPath,如您的示例中所示。我删除了尾随的//,并在当前路径匹配任何路径时简单地进行匹配,同时考虑隐式后代或self,如您的示例所示

您可能希望将for表达式包装在函数中,并调用该函数以将当前路径的串联映射到列表中的任何路径

在其当前形式中,您还需要提供通向更深路径的路径,或者您必须实现一个复制祖先节点的方法


无论如何,我认为这是一种足够简单的方法,不一定模仿xsl:evaluate,而是模仿基于路径的模式匹配,正如您的问题所暗示的那样。

我意识到我可以通过xslt实现这一点。但是,如果路径在运行时以字符串形式传递,则不容易。您能否更详细地解释为什么addressLine和zip会出现在输出中,尽管没有与它们匹配的路径?为什么id被删除而zip没有?addressLine和zip出现是因为地址存在,并且没有其他排除项存在。我得到的是唯一的叶子elements@mohan,这就是为什么我以当前的形式写,你还需要提供通向更深层路径的路径,或者,您必须实现类似于fn:snapshot的函数来复制祖先节点。。这是很自然的,因为你无法匹配你不知道的东西——祖先不匹配模式,直到在更深层次上。
<Employee>
    <Address>
        <addressLine1>Dummy Line 1</addressLine1>
        <zip>535270</zip>
    </Address>
    <Department>
        <name>development</name>
    </Department
</Employee>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs" 
    version="2.0">

    <xsl:strip-space elements="*" />

    <xsl:output indent="yes" />

    <xsl:variable name="patterns" as="xs:string*">
        <xsl:sequence select="(
            'foo/bar',
            'foo/test',
            'foo/bar/zed')" />
    </xsl:variable>

    <xsl:template match="node()[true() = (
        for $p in $patterns 
        return ends-with(
            string-join(current()/ancestor-or-self::*/name(), 
            '/'), $p))]">
        <xsl:copy>
            <xsl:apply-templates />
        </xsl:copy>
    </xsl:template>

    <xsl:template match="text()" />

</xsl:stylesheet>