Xpath编译不处理'撇号

时间:2014-09-18 18:21:08

标签: java xml xslt xpath

我有以下代码来查找所需节点的类型。

  private void handleDemote(CalendarCustomization calendar)
{
    String name = calendar.getName();
    Node node = (Node)reader.read("/APIBusinessObjects/Calendar[Name='" + name + "']/Type", XPathConstants.NODE);
   ...}

  public Object read(String expression, QName returnType)
{
    try
    {
        XPathExpression xPathExpression = xPath.compile(expression);
        return xPathExpression.evaluate(xmlDocument, returnType);
    }
    catch (XPathExpressionException ex)
    {
        ex.printStackTrace();
        return null;
    }
}

我想解析的xml有以下内容

 <Calendar>
    <BaseCalendarObjectId xsi:nil="true" />
    <HoursPerDay>8</HoursPerDay>
    <HoursPerMonth>173.3</HoursPerMonth>
    <HoursPerWeek>40</HoursPerWeek>
    <HoursPerYear>2080</HoursPerYear>
    <IsDefault>0</IsDefault>
    <IsPersonal>0</IsPersonal>
    <Name>test&apos;sCal</Name>

getName函数返回test'sCal.So name = test'sCal。 问题在于撇号,因为表达式包含单个额外引用。它缩短了导致表达式出错的名称。 请建议。

3 个答案:

答案 0 :(得分:1)

您需要在表达式中使用双引号。

(Node)reader.read("/APIBusinessObjects/Calendar[Name=\"" + name + "\"]/Type", XPathConstants.NODE);

答案 1 :(得分:1)

根据this answer,您应该能够在Java中使用XPath变量,这是解决此问题的正确方法。

您可以定义通用变量解析器:

class MapVariableResolver implements XPathVariableResolver {
  // local store of variable name -> variable value mappings
  Map<String, String> variableMappings = new HashMap<String, String>();

  // a way of setting new variable mappings 
  public void setVariable(String key, String value)  {
    variableMappings.put(key, value);
  }

  // override this method in XPathVariableResolver to 
  // be used during evaluation of the XPath expression      
  @Override
  public Object resolveVariable(QName varName) {
    // if using namespaces, there's more to do here
    String key = varName.getLocalPart();
    return variableMappings.get(key);
  }
}

修改您的read()方法,如下所示:

public Object read(String expression, QName returnType, XPathVariableResolver vr)
{
    try
    {
        xPath.setXPathVariableResolver(vr != null ? vr : new MapVariableResolver());
        XPathExpression xPathExpression = xPath.compile(expression);
        return xPathExpression.evaluate(xmlDocument, returnType);
    }
    catch (XPathExpressionException ex)
    {
        ex.printStackTrace();
        return null;
    }
}

然后执行此操作:

String name = calendar.getName();
MapVariableResolver vr = new MapVariableResolver() ;
vr.setVariable("name", name);

Node node = (Node)reader.read("/APIBusinessObjects/Calendar[Name = $name]/Type",
                              XPathConstants.NODE, vr);

答案 2 :(得分:0)

对于一般解决方案(即,当您不知道输入是否包含单引号,双引号或两者)时:

  1. 如果你有XPath 2.0,我猜你不用你的Java代码判断,你可以用一对单引号替换每个单引号(用单引号分隔的字符串,就像你的那样)。 (见this answer。)

  2. 否则,您可以在XPath表达式中使用concat()根据需要将'"'"'"与其余字符串连接起来。见The Perils of XPath Expressions (Specifically, Escaping Quotes)。因此,对于您的示例数据,您的XPath表达式将显示为:

  3. -

     /APIBusinessObjects/Calendar[Name = concat('test', "'", 'sCal')]
    

    然后由您编写Java函数将test'sCal转换为'test', "'", 'sCal'。值得庆幸的是,concat()将提供与您提供的一样多的参数。