【问题标题】:How to pass variable parameter into XPath expression?如何将可变参数传递给 XPath 表达式?
【发布时间】:2015-05-20 14:29:54
【问题描述】:

我想将参数传递给 XPath 表达式。

(//a/b/c[x=?],myParamForXAttribute)

我可以用 XPath 1.0 做到这一点吗? (我试过string-join,但它在 XPath 1.0 中没有)

那我该怎么做呢?

我的 XML 看起来像

<a>
 <b>
  <c>
   <x>val1</x>
   <y>abc</y>
  </c>
  <c>
   <x>val2</x>
   <y>abcd</y>
  </c>
</b>
</a>

我想得到&lt;y&gt;元素值,其中x元素值为val1

我试过//a/b/c[x='val1']/y,但没用。

【问题讨论】:

  • 如果您使用的是 Axiom 库,您应该标记您的问题 Java,并期望得到包含一些 Java 的答案。
  • 您从一个问题开始(如何在 XPath 表达式中使用变量)。我有answered that below。现在,您添加了另一个问题(您的新 XPath,它不使用变量并尝试选择 完全不同的 元素,不起作用)。为您的新问题添加一个新问题,并包含足够的细节和上下文来重现您的问题 - 您在这里没有这样做。
  • 顺便说一句,为什么要打扰//a/b/c?如果您打算使用递归搜索的所有性能影响(这很愚蠢,但这就是您使用// 而不是/ 开始时所做的事情),不妨使用//x[.='val1']/../y,并且不需要关心ab

标签: xml xpath axiom xpath-1.0


【解决方案1】:

鉴于您使用的是 Axiom XPath 库,而后者又使用 Jaxen,您需要按照以下三个步骤以完全稳健的方式执行此操作:

  • 创建一个SimpleVariableContext,并调用context.setVariableValue("val", "value1") 为该变量赋值。
  • 在您的 BaseXPath 对象上,调用 .setVariableContext() 以传递您分配的上下文。
  • 在您的表达式中,使用/a/b/c[x=$val]/y 来引用该值。

考虑以下几点:

package com.example;

import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.impl.common.AxiomText;
import org.apache.axiom.om.util.AXIOMUtil;
import org.apache.axiom.om.xpath.DocumentNavigator;
import org.jaxen.*;

import javax.xml.stream.XMLStreamException;

public class Main {

    public static void main(String[] args) throws XMLStreamException, JaxenException {
        String xmlPayload="<parent><a><b><c><x>val1</x><y>abc</y></c>" +
                                        "<c><x>val2</x><y>abcd</y></c>" +
                          "</b></a></parent>";
        OMElement xmlOMOBject = AXIOMUtil.stringToOM(xmlPayload);

        SimpleVariableContext svc = new SimpleVariableContext();
        svc.setVariableValue("val", "val2");

        String xpartString = "//c[x=$val]/y/text()";
        BaseXPath contextpath = new BaseXPath(xpartString, new DocumentNavigator());
        contextpath.setVariableContext(svc);
        AxiomText selectedNode = (AxiomText) contextpath.selectSingleNode(xmlOMOBject);
        System.out.println(selectedNode.getText());
    }
}

...作为输出发出:

abcd

【讨论】:

  • 能否请您发布代码 sn-p 作为上述答案的示例。 String xmlPayload="&lt;parent&gt;&lt;a&gt;&lt;c&gt;name1&lt;/c&gt;&lt;/a&gt;&lt;b&gt;name2&lt;/b&gt;&lt;/parent&gt;"; OMElement xmlOMOBject= AXIOMUtil.stringToOM(xmlPayload);SimpleVariableContext svc=new SimpleVariableContext(); svc.setVariableValue("part1",key1); svc.setVariableValue("part2",key2); String xpartString="$part1$part2"; DocumentNavigator nav=new DocumentNavigator(); BaseXPath contextpath=new BaseXPath(xmlPayload,nav); contextpath.setVariableContext(svc); contextpath.selectSingleNode(xmlOMOBject);
  • @user2694734,从完全准备好运行的复制器开始会更容易。也许把它放在一个要点中(gist.github.com),让任何想要提出更改的人都可以分叉?
  • @user2694734, ...几年后,我现在添加了一个工作示例。
【解决方案2】:

这取决于您使用 XPath 的语言。

在 XSLT 中:

 "//a/b/c[x=$myParamForXAttribute]"

请注意,与上面的方法不同,以下三个对XPath injection attacks 开放,并且永远不应与不受控制或不受信任的输入一起使用;为避免这种情况,请使用您的语言或库提供的机制来带外传递变量。 [Credit:Charles Duffy]

在 C# 中:

String.Format("//a/b/c[x={0}]", myParamForXAttribute);

在 Java 中:

String.format("//a/b/c[x=%s]", myParamForXAttribute);

在 Python 中:

 "//a/b/c[x={}]".format(myParamForXAttribute)

【讨论】:

  • 我用我的 xml 编辑了我的问题。请看一看。 x 是 c 的子元素
  • 我的场景是纯 Xpath。评估的 xpath 被发送到 java 程序。所以我想要纯 xpath 表达式中的解决方案
  • 没有用于变量评估的纯 XPath 技术;这取决于我所展示的托管语言。
  • 我不同意用于生成 XPath 的字符串格式化是一种好习惯;在此处给出的所有语言中——C#、Java 等——都可以使用将变量传递给 XPath 库的本地方法,并且应该优先使用。
  • 是的,如果您的 XPath 库提供了以类似于 XSLT 的方式解释变量的工具,请务必使用它。由于 OP 最初并没有说明他的语言/图书馆,我一般回答。许多初学者希望有一个纯 XPath 解决方案用于在 XPath 中嵌入变量,但实际上并没有;因此,保留这个一般性答案是有价值的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-27
  • 1970-01-01
  • 2012-05-22
  • 1970-01-01
  • 2015-06-09
相关资源
最近更新 更多