如何在XMLDOM子集类型中用数据库目录替代Define引用DTD
如何用Oracle目录对象实现DEFINE变量引用DTD的效果
问题背景
通过DEFINE命令定义变量note_dtd_path,并在XML的SYSTEM标识符中以¬e_dtd_path引用DTD文件时,可正常获取DOCTYPE信息;但使用CREATE DIRECTORY创建目录对象后,尝试用$DIR288571/note.dtd引用文件时触发ORA-31001错误,需实现与DEFINE变量相同的效果。
原因分析
DEFINE的&变量是SQL*Plus预替换机制,会在PL/SQL代码执行前将变量替换为实际物理路径,XML解析器拿到的是完整有效路径。- 目录对象的
$语法仅在Oracle特定API(如UTL_FILE)中被识别,XML解析器无法解析该语法,会直接将$DIR288571当作路径的一部分,导致路径无效触发错误。
解决方案
方案一:动态查询目录路径并拼接XML字符串
先从数据字典视图中获取目录对象对应的物理路径,再动态拼接XML内容,确保XML解析器拿到有效路径:
declare doc dbms_xmldom.DOMDocument; dt dbms_xmldom.DOMDOCUMENTTYPE; n dbms_xmldom.DOMNode; v_dtd_path varchar2(1000); begin -- 查询目录对象对应的物理路径 select directory_path into v_dtd_path from all_directories where directory_name = 'DIR288571'; -- 动态拼接XML内容,替换DTD路径 doc := dbms_xmldom.newDomDocument('<?xml version="1.0"?> <!DOCTYPE note SYSTEM "' || v_dtd_path || '/note.dtd"> <note> <to>Tove</to> <from>Jani</from> <heading>Reminder</heading> <body></body> </note> '); dt := dbms_xmldom.getDoctype(doc); dbms_output.put_line ('docType name : ' || dbms_xmldom.getname(dt)); n := dbms_xmldom.makeNode(dt); dbms_output.put_line('systemID : ' || dbms_xmldom.getsystemid(dt)); dbms_xmldom.freeDocument(doc); end; /
注意:执行该代码的用户需具备访问
ALL_DIRECTORIES视图的权限;若目录为当前用户创建,也可使用USER_DIRECTORIES视图。
方案二:设置XML解析器的基础URL
通过DBMS_XSLPROCESSOR.setBaseURL指定解析器的基础路径,XML的SYSTEM标识符只需填写DTD文件名:
declare doc dbms_xmldom.DOMDocument; dt dbms_xmldom.DOMDOCUMENTTYPE; n dbms_xmldom.DOMNode; v_dtd_path varchar2(1000); parser dbms_xmldom.DOMParser; begin select directory_path into v_dtd_path from all_directories where directory_name = 'DIR288571'; -- 创建解析器并设置基础URL(需添加file://协议前缀) parser := dbms_xmldom.newDOMParser; dbms_xslprocessor.setBaseURL(parser, 'file://' || v_dtd_path || '/'); -- 解析XML,SYSTEM仅需指定DTD文件名 dbms_xmldom.parse(parser, '<?xml version="1.0"?> <!DOCTYPE note SYSTEM "note.dtd"> <note> <to>Tove</to> <from>Jani</from> <heading>Reminder</heading> <body></body> </note> '); doc := dbms_xmldom.getDocument(parser); dt := dbms_xmldom.getDoctype(doc); dbms_output.put_line ('docType name : ' || dbms_xmldom.getname(dt)); n := dbms_xmldom.makeNode(dt); dbms_output.put_line('systemID : ' || dbms_xmldom.getsystemid(dt)); dbms_xmldom.freeDocument(doc); dbms_xmldom.freeParser(parser); end; /
内容的提问来源于stack exchange,提问作者장인태
相关产品推荐
相关产品推荐

