Here is the code.
PROCEDURE GetPhrases(pXMLin VARCHAR2,pXMLout OUT VARCHAR2)IS
/*
<availablephrases>
<PHRASES>
<PHRASE id=x userinput=y>
<DESC/>
<APPENDAGES>
<PHRASE id=x>
<DESC/>
</PHRASE>
<EXCEPTIONS>
<PHRASE id=x>
<DESC/>
</PHRASE>
</PHRASE>
</PHRASES>
</availablephrases>
<availablepostscript>
<PHRASES>
<PHRASE id=x userinput=y>
<DESC/>
</PHRASE>
</availablepostscript>';
*/
/* CURSOR curPhrases(lDocID template_phrase_control.tpc_doc_id %TYPE) IS
SELECT tpc_phrase_id,phc_phrase,TRIM(phc_append_user_input) AS phc_append_user_input,phc_phrase_type
FROM template_phrase_control,phrase_control
WHERE tpc_phrase_id=phc_phrase_id AND tpc_doc_id = lDocID AND
phc_phrase_type IN ('PH','PS') AND
NOT EXISTS(SELECT 1 FROM template_phrase_rules
WHERE tpr_doc_id=tpc_doc_id AND tpr_phrase_id=tpc_phrase_id)
ORDER BY tpc_seq_id;
*/
CURSOR curPhrases(lDocID template_phrase_control.tpc_doc_id %TYPE) IS
SELECT tpc_phrase_id,phc_phrase,TRIM(phc_append_user_input) AS phc_append_user_input,phc_phrase_type
FROM template_phrase_control,phrase_control
WHERE tpc_phrase_id=phc_phrase_id AND tpc_doc_id = lDocID AND
phc_phrase_type IN ('PH','PS')
ORDER BY tpc_seq_id;
CURSOR curAppendAndExcept(lDocID template_phrase_control.tpc_doc_id %TYPE,
lPhraseID template_phrase_control.tpc_phrase_id %TYPE) IS
SELECT tpr_append_exception_phrase_id,tpr_type,phc_phrase,phc_append_user_input
FROM phrase_control,template_phrase_rules
WHERE phc_phrase_type='PH' AND phc_phrase_id=tpr_append_exception_phrase_id AND
tpr_phrase_id=lPhraseID AND tpr_doc_id=lDocID;
lDocID shareholder_ltr_text.slt_doc_id%TYPE;
lResult VARCHAR2(20000):='';
lExceptions VARCHAR2(10000):='';
lAppendages VARCHAR2(10000):='';
lPostScript VARCHAR2(5000):='';
BEGIN
GetPhraseParameters(pXMLin,lDocID);
--get phrases for document
FOR recPhrases IN curPhrases(lDocID) LOOP
--check if phrase or postscript
IF recPhrases.phc_phrase_type='PS' THEN
lPostScript:=lPostScript || GetPhraseText(recPhrases.tpc_phrase_id,
recPhrases.phc_append_user_input,
recPhrases.phc_phrase,'POSTSCRIPT') || '</POSTSCRIPT>';
ELSE
lResult:=lResult || GetPhraseText(recPhrases.tpc_phrase_id,
recPhrases.phc_append_user_input,
recPhrases.phc_phrase);
p('PHRASE=' || RECPHRASES.TPC_PHRASE_ID);
--find appendages and exceptions
FOR recAppendAndExcept IN curAppendAndExcept(lDocID,recPhrases.tpc_phrase_id) LOOP
IF recAppendAndExcept.tpr_type=mAPPENDAGE THEN
lAppendages:=lAppendages || GetPhraseText(recAppendAndExcept.tpr_append_exception_phrase_id,
recAppendAndExcept.phc_append_user_input,
recAppendAndExcept.phc_phrase) || '</PHRASE>';
ELSIF recAppendAndExcept.tpr_type=mEXCEPTION THEN
lExceptions:=lExceptions || GetPhraseText(recAppendAndExcept.tpr_append_exception_phrase_id,
recAppendAndExcept.phc_append_user_input,
recAppendAndExcept.phc_phrase) || '</PHRASE>';
END IF;
END LOOP;
--add to main xml structure
lResult:=lResult || '<APPENDAGES>' || lAppendages || '</APPENDAGES>' ||
'<EXCEPTIONS>' || lExceptions || '</EXCEPTIONS></PHRASE>' ;
lAppendages:='';lExceptions:='';
END IF;
END LOOP;
--get postscript for document
pXMLOut:='<availablephrases>' || lResult || '</availablephrases>' ||
'<availablepostscript>' || lPostscript || '</availablepostscript>';
END GetPhrases;