2016-03-22 2 views
0

Ich habe ein wenig gesucht und kann nicht ein ähnliches Szenario zu dem, was ich versuche, zu finden.Parsing nur gültige XML in Oracle Stored Procedure

Ich habe den folgenden Code, der zuerst einen Cursor erstellt, der mit 1) gefüllt wird xml 2) ID.

Dies funktioniert gut, bis eine fehlerhafte xml Zeile getroffen wird (in der zweiten SELECT Anweisung), dann bricht es die Prozedur ab und wird nicht fortgesetzt. Ich muss einen Weg finden, schlechtes XML in der zweiten Auswahlanweisung zu überspringen und den Cursor weiter zu bauen. Hier

ist der Code:

DECLARE 
COUNTER NUMBER; 

CURSOR CXD_ID_UPDATE IS 
    WITH 
XMLDATA 
    AS 
(
SELECT XMLTYPE(X.XMLDOC) XMLD, X.CXD_ID 
FROM 
    C_XML_DOC X RIGHT OUTER JOIN CPS_POT P ON X.CXD_ID = P.CXD_ID 
    WHERE P.CXD_ID IS NOT NULL 
) 
SELECT XT.SCAN_DOC_ID AS SCAN_DOC_ID 
,X.CXD_ID AS CXD_ID 
FROM XMLDATA X, CPS_DOCUMENT DOC, 
XMLTABLE('/HXML/BATCH/FOLDER/DOCUMENTS/DOCUMENT' 
PASSING X.XMLD 
COLUMNS SCAN_DOC_ID VARCHAR2(50) PATH '@ScanDocID') XT 
WHERE REGEXP_LIKE(XT.SCAN_DOC_ID,'^\d+(\.\d+)?$', '') 
AND XT.SCAN_DOC_ID = DOC.DOC_ID; 
BEGIN 
COUNTER := 0; 
FOR REC IN CXD_ID_UPDATE 
LOOP 
BEGIN 
    UPDATE DOCUMENT SET CXD_ID = REC.CXD_ID WHERE DOC_ID = REC.SCAN_DOC_ID ; 
    COUNTER := COUNTER + 1; 

    EXCEPTION WHEN OTHERS THEN 
    CONTINUE; 
    END; 
END LOOP; 
DBMS_OUTPUT.PUT_LINE('UPDATED: ' || COUNTER || ' DOCUMENTS'); 
END; 
+0

ist es möglich, die Daten für uns in Ihrem Code zu füllen, damit wir Ihr Problem reproduzieren können? Ersetzen Sie Ihre 'SELECT FROM (meine Tabellen)' durch 'SELECT 'code1', 'value1' FROM DUAL union alle SELECT 'code2', 'value2' FROM DUAL ...' –

+0

Bitte definieren Sie, was Sie mit _bad xml_ bedeuten. Speichern Sie XML als Text in einer Datenbanktabellenspalte (z. B. varchar2 oder clob-Spalte)? Können Sie erzwingen, dass nur "gültiges" XML in die Tabelle eingefügt wird? – user272735

+0

XML ist in einer Clob-Spalte und nein, wir haben nicht die Kontrolle über einige der XML, die in die Tabelle kommen, so dass wir nur "gültiges" XML erzwingen können. Wenn ich schlechtes XML sage, kann ich nicht korrekt geparst werden. –

Antwort

0

Für diejenigen, die eine Antwort auf diese hier wollte es ist.

I erstellt zunächst eine neue Funktion:

create or replace function isWellFormedXML(P_XML_CONTENT CLOB,   
P_ERROR_MESSAGE OUT VARCHAR2) 
return number 
as 
    PARSING_ERROR exception; 
    PRAGMA EXCEPTION_INIT(PARSING_ERROR , -31011); 
    V_VALID_XML XMLTYPE; 
begin 
    V_VALID_XML := XMLTYPE(P_XML_CONTENT); 
    V_VALID_XML := NULL; 
return 1; 
exception 
when PARSING_ERROR then 
    P_ERROR_MESSAGE := DBMS_UTILITY.FORMAT_ERROR_STACK() ||   DBMS_UTILITY.FORMAT_ERROR_BACKTRACE(); 
    return 0; 
when others then 
    RAISE; 
end; 

Dies ist die Hauptfunktion dieses Dienstprogramm, das Dienstprogramme.

DECLARE 
V_ERROR_MSG VARCHAR2(4000); 
COUNTER NUMBER(10); 
BEGIN 
COUNTER := 0; 
FOR R IN ( 
SELECT X.CXD_ID CXD, 
    X.XMLDOC XML FROM XML_DOC X, POT P WHERE P.CXD_ID = X.CXD_ID 
) LOOP 
BEGIN 
    IF(isWellFormedXML(R.XML,V_ERROR_MSG)) = 1 THEN 
     FOR L IN (
     SELECT D.SCAN_DOC_ID DOCID 
     FROM DOCUMENT DOC, xmltable 
     ('/HXML/BATCH/FOLDER/DOCUMENTS/DOCUMENT' 
      PASSING XMLTYPE.CREATEXML(R.XML) 
      COLUMNS SCAN_DOC_ID VARCHAR2(50) PATH '@ScanDocID' 
     ) D 
     WHERE REGEXP_LIKE(D.SCAN_DOC_ID,'^\d+(\.\d+)?$', '') 
     AND D.SCAN_DOC_ID = DOC.DOC_ID 
    ) LOOP 
     BEGIN 
     COUNTER := COUNTER + 1; 
     --DBMS_OUTPUT.put_line('CXD '|| R.CXD || ' DOCID ' || L.DOCID); 
     END; 
     END LOOP; 
    END IF; 
    EXCEPTION 
    WHEN no_data_found THEN 
     NULL; 
    END; 
END LOOP;  
DBMS_OUTPUT.put_line('TOTAL NUMBER OF DOCUMENTS : ' || COUNTER); 
END;