【问题标题】:Xpath compile not handling ' apostropheXpath 编译不处理'撇号
【发布时间】:2014-09-18 18:21:08
【问题描述】:

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

  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 。 问题在于撇号,因为表达式包含一个额外的引号。它缩短了导致表达式错误的名称。 请提出建议。

【问题讨论】:

    标签: java xml xslt xpath


    【解决方案1】:

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

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

    【讨论】:

    • 在 XPath 中,如果使用双引号来分隔字符串,那么字符串中的单引号(撇号)只是文字。反之亦然。因此,只要您输入的任何日历名称中没有双引号,此解决方案就可以工作。如果您不确定后者,您可以在从名称字符串构造 XPath 表达式时尝试将所有 ' 替换为 &amp;apos;。但我还没有检查这是否真的有效。
    • OK 抓紧最后一点。 :-) 看看我的回答。
    【解决方案2】:

    根据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);
    

    【讨论】:

      【解决方案3】:

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

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

      -

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

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

      【讨论】:

        猜你喜欢
        • 2018-12-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-09-12
        • 1970-01-01
        • 2015-08-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多