XPath 表达式忽略带有谓词引用子元素的命名空间

XPath expression ignoring namespaces with predicates referencing child elements

我正在做一个迄今为止依赖设置的项目: DocumentBuilderFactory.setNamespaceAware(false); 实现命名空间灵活的 xpath(忽略可能传入的任何前缀)。

这仅在过去有效,因为正在使用 xalan 转换器,尽管从技术上讲,将命名空间感知设置为 false 的行为充其量应该是未定义的,但对于给定的 xml,xalan 将以下 xpath 视为有效。

xml:

<t:GiftBasket xmlns:t="http://tastyTreats.com/giftbasket">
    <t:Fruit>
        <t:Apple>
            <t:Name>Cameo</t:Name>
            <t:Color>Red</t:Color>
            <t:TasteDescription>Juicy, crisp, and sweet with just a touch of tart, the Cameo is thought to come from both the Red and the Yellow Delicious.</t:TasteDescription>
        </t:Apple>
        <t:Apple>
            <t:Name>Empire</t:Name>
            <t:Color>Red</t:Color>
            <t:TasteDescription>The interior is crisp and creamy white while being firmer than the McIntosh, so it makes for a good cooking apple. </t:TasteDescription>
        </t:Apple>
        <t:Apple>
            <t:Name>Granny Smith</t:Name>
            <t:Color>Green</t:Color>
            <t:TasteDescription>Hard feel, crisp bite, and extremely tart taste. Some prefer to cook it, which sweetens it up.</t:TasteDescription>
        </t:Apple>
    </t:Fruit>
    <t:Candy>
        <t:Chocolate>Dark</t:Chocolate>
    </t:Candy>
</t:GiftBasket>

xpath:

/GiftBasket/Fruit/Apple[Color='Red'][contains(TasteDescription,'sweet')]

在切换到 xslt 2.0 时,我切换到了 Saxon-HE 转换器。撒克逊人是一个更精确的变压器(IMO 的好东西)。它识别出这些 xpath 表达式是 "wrong",我现在必须修复像上面那样的一堆 xpath 表达式来工作,而不管引用的名称空间前缀如何(客户端可以选择将 URI http://tastyTreats.com/giftbasket 作为前缀作为 'fluffybunnies'据我所知)

我收到了其他关于如何利用 local-name() 功能来实现我需要的大部分功能的好建议 here。我的 xpath 现在显示为:

/*[local-name()='GiftBasket']/*[local-name()='Fruit']/*[local-name()='Apple'][Color='Red'][contains(TasteDescription,'sweet')]

然而,这仍然不准确,因为谓词中引用的元素仍然引用确切的元素名称 ColorTasteDescription,而命名空间不灵活。有没有更好的方法为口味描述中包含 'sweet' 的所有红苹果编写 xpath,同时保持名称空间前缀灵活?

正如您提到的 XSLT 2.0,在 XSLT 2.0 中您可以定义

<xsl:stylesheet xpath-default-namespace="http://tastyTreats.com/giftbasket" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

然后使用没有前缀名称的 XPath 表达式和 XSLT 匹配模式到该特定命名空间中的 select 元素,也就是说,路径 /GiftBasket/Fruit/Apple[Color='Red'][contains(TasteDescription,'sweet')] 应该可以很好地匹配 select 元素在具有命名空间 http://tastyTreats.com/giftbasket.

的输入文档中

如果您将 JAXP XPath API 与 Saxon 9 一起使用,请参阅 https://saxonica.plan.io/boards/3/topics/1649 了解如何使用 API 设置这样的默认名称空间:

((XPathEvaluator)xpath).getStaticContext().setDefaultElementNamespace("http://tastyTreats.com/giftbasket");