使用XPATH查询以查找包含关键字的属性

3

我正在尝试在多个不同节点的多个属性中搜索内容

以下是如何在一个属性中查找它

//*[contains(@name,'KEYA')]

示例XML:

<cars>

<car model="2000" name="Awesome KEYA Car" name2="somethine else">Brand1</car>
<car model="2005" name="Awesome Car" name2="KEYA something else">Brand 2</car>
<car name="Awesome Car" name2="somethine else">Brand1</car>
<car dontmatch="KEYA" name2="somethine else">Brand3333</car>

</cars>

我真正想要的是能够匹配超过10个属性的东西(它只需要匹配白名单中的属性)。
//*[contains((@name or @name2 or @name3),'KEYA')]

使用XPATH 1.0。有没有关于如何做到这一点的想法?除了重复包含之外,尝试了几种方法但都没有成功。


好问题,+1。请看我的答案,其中包含一个完整、简短和易于理解的一行XPath表达式解决方案,它可以让您轻松地以最紧凑和自然的形式指定要搜索的属性名称。同时也提供了解释。 - Dimitre Novatchev
3个回答

5
这对我有用。
/cars/car/@*[contains(.,'KEYA')]/parent::*

enter image description here

好的,在编辑之后,我建议

/cars/car/@*[name()!='dontmatch'][contains(.,'KEYA')]/parent::*

输入图像描述

如果您想排除多个属性,那么您需要指定其他谓词(方括号中的内容)。XPath没有提供一种排除属性名称集合的方法,除非您可以使用startswith()contains()或类似的方式来约束该集合。

在其他库中有方便的查询XML的方法,例如,如果您使用.NET,则可以使用LINQ-to-XML。这将允许您更简洁地指定这些类型的查询。但这是完全不同的API。


它需要在特定的属性列表中找到,而不是所有属性。 - dr. evil
回复:“Xpath没有提供一种方法...”。拜托,你为什么这么肯定? :) 其他解决方案证明了这个说法是错误的。更不用说XPath 2.0了。至于所谓的“XPath可视化工具”,我想知道它何时才能获得我自己的、更早期的、同名工具的所有功能——或者这只是我的一厢情愿? - Dimitre Novatchev
Dimitre,请息怒。每次你在我的答案或帖子上发表评论时,都是敌对的、对抗性的或批评性的。这样做没有必要。我不知道你为什么对我有如此个人的敌意。没有理由。请停止。我很抱歉重复使用你建造的工具的名称。这并不是一种侮辱。请放松。 - Cheeso

4

使用:

/*/*[@*
        [contains('|name|name1|name2|name3|name4|',
                  concat('|',name(),'|')
                  )
       and
         contains(., 'KEYA')
        ]
       ]

以下是由XPath Visualizer生成的选择结果:

enter image description here

解释:

您可以在字符串中指定要搜索的所有属性名称。使用“管道分隔符(|)”可确保即使某个名称是另一个名称的开头,只有在存在单独的、以管道分隔的子字符串时,才会将其包含在搜索中。


好的,已标记为完成并感谢您的解释。 - dr. evil
/*/* ه’Œ //* ن¹‹é—´وœ‰ن»€ن¹ˆهŒ؛هˆ«هگ—ï¼ں - dr. evil
@恶魔博士:是的,/*/*选择XML文档顶层元素的所有子元素,而//*选择文档中的所有元素。 - Dimitre Novatchev

1

怎么样:

//*[contains(@name,'KEYA') or contains(@name2,'KEYA')]

你可以采用Cheeso的答案,像这样做:

/cars/car/@*[contains(.,'KEYA') and local-name() != 'dontmatch']/parent::*

无论如何,你都必须构建XPath语句,从属性白名单中选择(我的示例),或者从属性黑名单中排除(修改后的Cheeso示例)。

在Cheeso的工作基础上,这可能简化了构建黑名单:

//@*[contains(.,'KEYA') and not(contains('dontmatch,dontmatch2', local-name()))]/parent::*

或者作为白名单:

//@*[contains(.,'KEYA') and contains('name,name2', local-name())]/parent::**

是的,那样可以解决问题,但管理起来会非常丑陋 :) - dr. evil
@Kev 我不是在搜索全部。 - dr. evil
谢谢,我希望能找到类似这样的东西“contains((@name or @name2 or @name3),'KEYA')”,但我想我必须使用这么多包含来白名单一些东西。 - dr. evil
我喜欢它,但我认为这是一个糟糕的hack,可能会导致意外的错误,即这将返回不正确的结果“//@*[contains(.,'KEYA') and contains('name2', local-name())]”。 - dr. evil
1
@dr. evil 如果没有 /parent::*,你只会选择属性节点,而 /parent::* 则选择包含这些属性的父 XML 节点。 - Kev
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接