Reputation: 264
I have an Oracle DB that contains an XML Column called CONTENT
of this kind:
<?xml version="1.0"?>
<PAGE>
<INFO>
<ID>324374</ID>
<PAGE>ANE_CSC</PAGE>
</INFO>
<CAMPS>
<CAMP KEY_CAMP="ACCESS_CONTROL">456675</CAMP>
<CAMP KEY_CAMP="IDEN_ANAG">1458</CAMP>...
</CAMPS>
</PAGE>
I'm trying to extract the IDEN_ANAG
value (so: 1458
) in a Excel cell, however I've no idea how to elaborate XML data correctly in VBA.
I have tried a few things (commands like getStringVal(), getClob(), EXTRACT()
) and cannot figure out a solution that would work.
This is what I'm currently trying to do:
Cmd.CommandText = "select XMLTYPE('<CAMP>'||CONTENT||'</CAMP>').getStringVal() from table WHERE ID = 324374
Set rs = Cmd.Execute()
Do While Not rs.EOF
WSP1.Cells(CellWrite, 1).Value = rs.Fields(0).Value
CellWrite = CellWrite + 1
rs.MoveNext
Loop
I know that the code above isn't actually extracting the specific ID, but I'm fairly desparate to at least start with extracting the whole XML and then trying to find a solution for just specific part of it.
While I'm almost sure that I'm just making a mistake in the code, I've tried several different results based on internet searches, using different functions etc and I've always run into errors like Runtime error
or the code above gives me the error as Runtime error: Character string buffer too small
.
Any suggestions on how to extract the specific data would be appreciated.
Upvotes: 0
Views: 139
Reputation: 6751
It is an Oracle error and appears when you try to put some big string into VARCHAR
datatype.
You can check this documentation article, section "Selecting XML Data Using XMLType Methods":
You can select XMLType data using PL/SQL, C, or Java. You can also use the XMLType methods
getClobVal()
,getStringVal()
,getNumberVal()
, andgetBlobVal(csid)
to retrieve XML data as aCLOB
,VARCHAR
,NUMBER
, andBLOB
value, respectively.
So looks like your data is too big to fit in VARCHAR
that getStringVal()
returns, and you need to use getClobVal()
.
Also there's no need to create XML data by concatenation since it cannot handle all the serialization specifics (like symbols used in XML should be converted) and you can also face the same limitation of VARCHAR
length on concatenation. You need XMLElement
function for this:
select xmlelement("Current_date", sysdate) as date_xml, xmlelement("SpecialSymbols", 'Symbols > and < need conversion') as spec_symbols_xml from dual
DATE_XML | SPEC_SYMBOLS_XML :-------------------------------------- | :--------------------------------------------------------------------- <Current_date>2021-03-05</Current_date> | <SpecialSymbols>Symbols > and < need conversion</SpecialSymbols>
db<>fiddle here
You can chech a bunch of XML manipulation functions to build XML, so use them instead of string manipulations. For example, get query results as XML:
select dbms_xmlgen.getxml('select object_name, object_type from all_objects where rownum < 3') as result_clob from dual
| RESULT_CLOB | | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | <?xml version="1.0"?><br><ROWSET><br> <ROW><br> <OBJECT_NAME>ORA$BASE</OBJECT_NAME><br> <OBJECT_TYPE>EDITION</OBJECT_TYPE><br> </ROW><br> <ROW><br> <OBJECT_NAME>DUAL</OBJECT_NAME><br> <OBJECT_TYPE>TABLE</OBJECT_TYPE><br> </ROW><br></ROWSET><br> |
db<>fiddle here
But it is better to do all MXL manipulations in the database and retrieve plain results to VBA.
Upvotes: 0
Reputation: 168041
Use a proper XML parser. You can either use the query:
SELECT iden_anag
FROM table_name t
CROSS APPLY XMLTABLE(
'/PAGE/CAMPS'
PASSING XMLTYPE( t.content )
COLUMNS
iden_anag NUMBER PATH './CAMP[@KEY_CAMP="IDEN_ANAG"]'
)
WHERE id = 324374
or
SELECT XMLQUERY(
'/PAGE/CAMPS/CAMP[@KEY_CAMP="IDEN_ANAG"]/text()'
PASSING XMLTYPE( content )
RETURNING CONTENT
) AS iden_anag
FROM table_name
WHERE id = 324374
Which, for your sample data:
CREATE TABLE table_name ( id NUMBER, content CLOB );
INSERT INTO table_name ( id, content ) VALUES (
324374,
'<?xml version="1.0"?>
<PAGE>
<INFO>
<ID>324374</ID>
<PAGE>ANE_CSC</PAGE>
</INFO>
<CAMPS>
<CAMP KEY_CAMP="ACCESS_CONTROL">456675</CAMP>
<CAMP KEY_CAMP="IDEN_ANAG">1458</CAMP>...
</CAMPS>
</PAGE>'
);
Both output:
| IDEN_ANAG | | --------: | | 1458 |
db<>fiddle here
Upvotes: 1