如何在 Oracle 中将字符串参数正确传递给 XPATH?

问题描述

如何将字符串参数传递给 EXTRACTVALUE

例如:

EXTRACTVALUE(fooColumn,'/foo/bar[@baz = "arg"]/@value')

如何用实参 "arg" 替换 :arg

简单的解决方案:

EXTRACTVALUE(fooColumn,'/foo/bar[@baz = "' || :arg || '"]/@value')

这里如何防止可能的“XPath”注入? 是否有 XPath 转义函数

解决方法

EXTRACTVALUE 已弃用,您应该改用 XMLQUERYXMLTABLE

您可以尝试使用 DBMS_ASSERT 包:

CREATE FUNCTION enquote_name (
  name IN VARCHAR2
) RETURN VARCHAR2
IS
BEGIN
  -- Wrap it in a function call to use the PL/SQL FALSE literal.
  RETURN DBMS_ASSERT.ENQUOTE_NAME(name,FALSE);
END;
/

那么:

SELECT XMLQUERY(
         ('/foo/bar[@baz='||ENQUOTE_NAME(:arg)||']/@value')
         PASSING fooColumn
         RETURNING CONTENT
       ) AS value
FROM   table_name

SELECT EXTRACTVALUE( foocolumn,'/foo/bar[@baz='||ENQUOTE_NAME(:arg)||']/@value')
         AS value
FROM   table_name

表:

CREATE TABLE table_name ( foocolumn ) AS
SELECT XMLTYPE(
'<foo><bar baz="abc" value="123" /><bar baz="def" value="456" /></foo>'
)
FROM DUAL;

输出,当 :argdef 时:

VALUE
456

如果您尝试将 :arg 用作 'abc"][@value="123',则查询返回零行(或引发 EXTRACTVALUE 的异常);但是,如果您尝试传递相同的值而不将其包装在对 ENQUOTE_NAME 的调用中(并包括 ENQUOTE_NAME 将添加的双引号),那么它将执行您试图避免的 XPATH 注入。

dbfiddle here