Oracle 提取几个 xpath 值

Oracle extract few xpath values

我正在尝试从此 xml
中提取三个 printerLocations printerLocations 存储在 printer/printer-header/elem 下,属性名称为 printerLocations

问题是如何在列表中获取结果 像“美国,英国,(空)”
或者像我可以这样查询的列格式:

select * from ( this xml query) where column1 = "USA"

这是一个示例 xml:

    <?xml version="1.0" encoding="UTF16" standalone="no" ?>
    <printer>
        <printer-header>
            <elem name="printerId">XROX101-19341</elem>
            <elem name="printerDate">05/11/19 12:27:48</elem>
            <elem name="printerLocations">
                <elem name="countryCd">USA</elem>
            </elem>
            <elem name="printerLocations">
                <elem name="countryCd">UK</elem>
            </elem>
            <elem name="printerLocations">
                <elem name="countryCd"/>
            </elem>
        </printer-header>
    </printer>

我尝试了什么:

select  XMLTYPE(xml_string).extract('/printer/printer-header/elem[@name="printerLocations"]/elem[@name="countryCd"]/text()').getStringVal()   from printers 

/

这只是美国的刺痛值

我希望得到的输出是一个 table 三列,

COUNTRY1     COUNTRY2     COUNTRY3
USA          UK           NULL

您可以使用 XMLTable 提取多个值,包括父元素值,例如:

select printerId, printerDate, countryCd
from xmltable(
  '/printer/printer-header/elem[@name="printerLocations"]'
  passing xmltype('<?xml version="1.0" encoding="UTF16" standalone="no" ?>
<printer>
    <printer-header>
        <elem name="printerId">XROX101-19341</elem>
        <elem name="printerDate">05/11/19 12:27:48</elem>
        <elem name="printerLocations">
            <elem name="countryCd">USA</elem>
        </elem>
        <elem name="printerLocations">
            <elem name="countryCd">UK</elem>
        </elem>
        <elem name="printerLocations">
            <elem name="countryCd"/>
        </elem>
    </printer-header>
</printer>')
  columns
    printerId varchar2(30) path './../elem[@name="printerId"]',
    printerDate varchar2(17) path './../elem[@name="printerDate"]',
    countryCd varchar2(3) path 'elem[@name="countryCd"]'
)
PRINTERID PRINTERDATE COUNTRYCD
XROX101-19341 05/11/19 12:27:48 USA
XROX101-19341 05/11/19 12:27:48 UK
XROX101-19341 05/11/19 12:27:48 null

您可以将 'printDate' 值转换为实际日期,假设它是固定格式。

无论哪种方式,您都可以将其用作内联视图或 CTE。

db<>fiddle

What I tried: select XMLTYPE(xml_string).extract('/printer/printer-header/elem[@name="printerLocations"]/elem[@name="countryCd"]/text()').getStringVal() from printers

这会将所有国家/地区值作为一个字符串;使用 XMLTable 而不是单独获取每个值,并允许您轻松获取其他数据,以及一次获取多个 XML 文档的数据。

由于您的字符串来自 table,因此变为:

select x.printerId, x.printerDate, x.countryCd
from printers p
cross apply xmltable(
  '/printer/printer-header/elem[@name="printerLocations"]'
  passing xmltype(p.xml_string)
  columns
    printerId varchar2(30) path './../elem[@name="printerId"]',
    printerDate varchar2(17) path './../elem[@name="printerDate"]',
    countryCd varchar2(3) path 'elem[@name="countryCd"]'
) x
PRINTERID PRINTERDATE COUNTRYCD
XROX101-19341 05/11/19 12:27:48 USA
XROX101-19341 05/11/19 12:27:48 UK
XROX101-19341 05/11/19 12:27:48 null

包裹在外部查询中,带有转换后的日期,如:

select * from (
  select
    printerId,
    to_date(printerDate, 'DD/MM/RR HH24:MI:SS') as printerDate,
    countryCd
  from printers p
  cross apply xmltable(
    '/printer/printer-header/elem[@name="printerLocations"]'
    passing xmltype(p.xml_string)
    columns
      printerId varchar2(30) path './../elem[@name="printerId"]',
      printerDate varchar2(17) path './../elem[@name="printerDate"]',
      countryCd varchar2(3) path 'elem[@name="countryCd"]'
  )
) x
where x.countryCd = 'USA'
PRINTERID PRINTERDATE COUNTRYCD
XROX101-19341 2019-11-05 12:27:48 USA

db<>fiddle


All I need is a table with three columns

你可以调整那个结果;但更简单的是,您可以使用类似的方法,按索引定位每个打印机位置:

select x.countryCd1, x.countryCd2, x.countryCd3
from printers p
cross apply xmltable(
  '/printer/printer-header'
  passing xmltype(p.xml_string)
  columns
    countryCd1 varchar2(3) path 'elem[@name="printerLocations"][1]/elem[@name="countryCd"]',
    countryCd2 varchar2(3) path 'elem[@name="printerLocations"][2]/elem[@name="countryCd"]',
    countryCd3 varchar2(3) path 'elem[@name="printerLocations"][3]/elem[@name="countryCd"]'
) x
COUNTRYCD1 COUNTRYCD2 COUNTRYCD3
USA UK null

db<>fiddle

您可以改为使用三个 XMLQuery 调用,但这会涉及更多的重复。

或者,如果您真的想要,您仍然可以使用原始提取物三次,并添加一个索引:

select
  XMLTYPE(xml_string).extract('/printer/printer-header/elem[@name="printerLocations"][1]/elem[@name="countryCd"]/text()').getStringVal() as countryCd1,
  XMLTYPE(xml_string).extract('/printer/printer-header/elem[@name="printerLocations"][2]/elem[@name="countryCd"]/text()').getStringVal() as countryCd2,
  XMLTYPE(xml_string).extract('/printer/printer-header/elem[@name="printerLocations"][3]/elem[@name="countryCd"]/text()').getStringVal() as countryCd3
from printers

... gets the same result.

无论哪种方式,您都必须事先知道您期望最终结果中有多少个值(列)。 (否则你必须使用动态 SQL...)