Author |
Message
|
TonyD |
Posted: Sun Apr 04, 2004 11:27 pm Post subject: Removing empty elements in output XML |
|
|
Knight
Joined: 15 May 2001 Posts: 540 Location: New Zealand
|
Is there any way to omit empty elements (e.g. <City></City>) from an output XML message without specifically testing whether the element is empty? |
|
Back to top |
|
 |
martinrydman |
Posted: Mon Apr 05, 2004 12:14 am Post subject: |
|
|
 Centurion
Joined: 30 Jan 2004 Posts: 139 Location: Gothenburg, Sweden
|
Hi,
To the best of my knowledge, no there isn't. I hav solved this problem in the past by writing a recursive PROCEDURE that visits each element generically and removes it if it's empty.
Hope this helps!
/Martin |
|
Back to top |
|
 |
Yanghui |
Posted: Tue Apr 13, 2004 8:51 am Post subject: |
|
|
Disciple
Joined: 08 May 2002 Posts: 151 Location: Dublin, Ireland
|
Hi, there,
It seems it's not that straight forward to remove those empty tags. I tried
Set reference = NULL;
and
DETACH reference;
but both ways also change <Element1></Element1> to <Element1/>.
Does anybody know why? Many thanks in advance.
Regards
-Yanghui |
|
Back to top |
|
 |
Yanghui |
Posted: Wed Apr 14, 2004 10:18 am Post subject: |
|
|
Disciple
Joined: 08 May 2002 Posts: 151 Location: Dublin, Ireland
|
Hi,
I try to call the recursive procedure to remove those empty tag but it seems only the first empty tag of each XML block removed. The rest of them still stay in the tree... By using trace, it looks like the reference jumped from one block to the next after the first empty tag is set NULL. I don't understand why. Can anybody see anything wrong in the ESQL? Many thanks in advance.
CREATE PROCEDURE RemoveEmptyElement(IN root REFERENCE)
BEGIN
DECLARE cursor REFERENCE TO root;
MOVE cursor FIRSTCHILD;
IF LASTMOVE(cursor) THEN
ELSE
IF CAST(cursor AS CHARACTER) = '' THEN
-- DELETE FIELD cursor;
SET cursor = NULL;
END IF;
END IF;
WHILE LASTMOVE(cursor) DO
CALL RemoveEmptyElement(cursor);
MOVE cursor NEXTSIBLING;
END WHILE;
END; |
|
Back to top |
|
 |
martinrydman |
Posted: Thu Apr 15, 2004 12:50 am Post subject: |
|
|
 Centurion
Joined: 30 Jan 2004 Posts: 139 Location: Gothenburg, Sweden
|
Hi!
Here's some code that actually works
Code: |
-- CALL from Main:
SET OutputRoot = InputRoot;
DECLARE OutMsg REFERENCE TO OutputRoot.XML;
CALL RemoveEmptyElements(OutMsg);
-- Recursive PROCEDURE:
CREATE PROCEDURE RemoveEmptyElements(INOUT Root REFERENCE)
BEGIN
DECLARE ClimbChildren BOOLEAN TRUE;
IF TRIM(Root) = '' THEN
DECLARE Elmnt REFERENCE TO Root;
DETACH Elmnt;
SET Elmnt = NULL;
SET ClimbChildren = FALSE;
END IF;
IF ClimbChildren THEN
DECLARE NxtSibl REFERENCE TO Root;
MOVE NxtSibl FIRSTCHILD;
WHILE LASTMOVE(NxtSibl) DO
DECLARE Child REFERENCE TO NxtSibl;
MOVE NxtSibl NEXTSIBLING;
CALL RemoveEmptyElements(Child);
END WHILE;
END IF;
END;
|
Note in particular the extra pointer NxtSibl, that is set before the recursive call. If you try to MOVE NEXTSIBLING after the call, the child to move from might have been removed, and so the MOVE fails!
HTH!
/Martin |
|
Back to top |
|
 |
Yanghui |
Posted: Fri Apr 16, 2004 3:00 am Post subject: |
|
|
Disciple
Joined: 08 May 2002 Posts: 151 Location: Dublin, Ireland
|
Hi, Martian,
Sorry for late reply. Just got chance to try it out.
The proble you spotted was absolutely right. Now it works. Thanks a lot for your help...
Best regards
-Yanghui |
|
Back to top |
|
 |
JustFriend |
Posted: Mon Jun 27, 2005 6:37 am Post subject: |
|
|
Novice
Joined: 30 May 2005 Posts: 22
|
Martin… thanks for your wonderful code for removing the painful blank xml tags. That was really wonderful.
I have modified a bit for removing the Carriage-Return (CR) and Line-Feed (LF) which also generates empty-tags in the output.
Please find below the code that I am using:
-- Recursive PROCEDURE:
CREATE PROCEDURE RemoveEmptyElements(INOUT Root REFERENCE)
BEGIN
DECLARE ClimbChildren BOOLEAN TRUE;
DECLARE CR CHAR CAST(CAST(X'0D' AS BLOB) AS CHAR CCSID InputRoot.MQMD.CodedCharSetId );
DECLARE LF CHAR CAST(CAST(X'0A' AS BLOB) AS CHAR CCSID InputRoot.MQMD.CodedCharSetId );
IF TRIM(Root) = '' THEN
DECLARE Elmnt REFERENCE TO Root;
DETACH Elmnt;
SET Elmnt = NULL;
SET ClimbChildren = FALSE;
END IF;
IF (POSITION(LF IN FIELDVALUE(Root)) > 0) AND (LENGTH(FIELDNAME(Root)) < 1 ) THEN
DECLARE Elmnt REFERENCE TO Root;
DETACH Elmnt;
SET Elmnt = NULL;
SET ClimbChildren = FALSE;
END IF;
IF (POSITION(CR IN FIELDVALUE(Root)) > 0) AND (LENGTH(FIELDNAME(Root)) < 1 ) THEN
DECLARE Elmnt REFERENCE TO Root;
DETACH Elmnt;
SET Elmnt = NULL;
SET ClimbChildren = FALSE;
END IF;
IF ClimbChildren THEN
DECLARE NxtSibl REFERENCE TO Root;
MOVE NxtSibl FIRSTCHILD;
WHILE LASTMOVE(NxtSibl) DO
DECLARE Child REFERENCE TO NxtSibl;
MOVE NxtSibl NEXTSIBLING;
CALL RemoveEmptyElements(Child);
END WHILE;
END IF;
END;
Please tell me if I am right else seeking your valuable advice.
Best Regards,
MOHD IQHBAL. |
|
Back to top |
|
 |
martinrydman |
Posted: Tue Jun 28, 2005 3:15 am Post subject: |
|
|
 Centurion
Joined: 30 Jan 2004 Posts: 139 Location: Gothenburg, Sweden
|
Hi,
Seems OK, and if it works, well then there's no problem
/Martin |
|
Back to top |
|
 |
x061294 |
Posted: Wed Jun 29, 2005 6:41 am Post subject: |
|
|
 Acolyte
Joined: 05 Apr 2005 Posts: 62
|
I've tried this code, and several people have responded how it works, but, I can't get it to work. I'm running 5.0.4 of broker on Windows.
Here is the statements that I used to create the XML
Code: |
Set OutputRoot.XML.A.B.C = InputRoot.XML.Customer.Name.FirstName;
Set OutputRoot.XML.A.B.D = InputRoot.XML.Customer.Name.Title;
Set OutputRoot.XML.A.B.Error = InputRoot.XML.Customer.Name.Error;
CREATE LASTCHILD OF OutputRoot.XML.A.B.C NAME 'ERROR' VALUE InputRoot.XML.Customer.Name.FirstName.Error; |
which generate the following XML
<A>
<B>
<C>
Fred
<ERROR></ERROR>
</C>
<D>Mr</D>
</B>
</A>
I then execute the code:
Code: |
DECLARE OutMsg REFERENCE TO OutputRoot.XML;
CALL RemoveEmptyElements(OutMsg);
CREATE PROCEDURE RemoveEmptyElements(INOUT Root REFERENCE)
BEGIN
DECLARE ClimbChildren BOOLEAN TRUE;
IF TRIM(Root) = '' THEN
DECLARE Elmnt REFERENCE TO Root;
DETACH Elmnt;
SET Elmnt = NULL;
SET ClimbChildren = FALSE;
END IF;
IF ClimbChildren THEN
DECLARE NxtSibl REFERENCE TO Root;
MOVE NxtSibl FIRSTCHILD;
WHILE LASTMOVE(NxtSibl) DO
DECLARE Child REFERENCE TO NxtSibl;
MOVE NxtSibl NEXTSIBLING;
CALL RemoveEmptyElements(Child);
END WHILE;
END IF;
END; |
and trace it through. The flow goes to the first if,
Code: |
IF TRIM(Root) = '' THEN |
which results in true, detaches and null's the whole tree, and ends. No matter what I do, the statement always results in true which means that i don't walk the tree.
2005-06-29 10:30:29.635307 5664 UserTrace BIP2539I: Node 'ABC_XML.Compute1': Finished evaluating expression 'TRIMBOTH(BOTH FROM Root) = ''' at (.ABC_XML_Compute1.RemoveEmptyElements, 6.19). This resolved to ''' = '''. The result was 'TRUE'.
Any ideas on why the trim of the root would come back as '' right out the bat? |
|
Back to top |
|
 |
mverh |
Posted: Wed Oct 26, 2005 12:50 pm Post subject: |
|
|
Voyager
Joined: 06 Mar 2002 Posts: 97
|
I need code like this...and like the last post by x061294 this code doesn't work for me either...since people posted it did work I am curious to know if it is a V2.1 versus V5 issue...in any case I am in the process of modifying it and wonder if anyone has as well and has a working copy for V5....thx...
Marc |
|
Back to top |
|
 |
elvis_gn |
Posted: Wed Oct 26, 2005 8:33 pm Post subject: |
|
|
 Padawan
Joined: 08 Oct 2004 Posts: 1905 Location: Dubai
|
Hi guys,
From the first post, i feel that TonyD was just trying to see if the field is empty, and if yes then not get it in the Output itself.....
Instead on running a procedure for this and looping through every element to see the length etc, why not use COALESCE with NULL.....
Regards. |
|
Back to top |
|
 |
JustFriend |
Posted: Wed Oct 26, 2005 11:59 pm Post subject: |
|
|
Novice
Joined: 30 May 2005 Posts: 22
|
For everybody's benefit, we request you to post the ESQL.
Thank you _________________ Best Regards,
Just Friend. |
|
Back to top |
|
 |
mverh |
Posted: Thu Oct 27, 2005 12:16 pm Post subject: |
|
|
Voyager
Joined: 06 Mar 2002 Posts: 97
|
Ok, I have got a fix to the code that works...kind of...
the new code looks like...
Code: |
CREATE COMPUTE MODULE recursiveCode_Compute
CREATE FUNCTION Main() RETURNS BOOLEAN
BEGIN
-- CALL CopyMessageHeaders();
CALL CopyEntireMessage();
DECLARE OutMsg REFERENCE TO OutputRoot.XML.[1];
CALL RemoveEmptyElements(OutMsg);
RETURN TRUE;
END;
-- Recursive PROCEDURE:
CREATE PROCEDURE RemoveEmptyElements(INOUT inXML REFERENCE)
BEGIN
DECLARE ClimbChildren BOOLEAN TRUE;
IF TRIM(inXML) = '' THEN
DECLARE Elmnt REFERENCE TO inXML;
DETACH Elmnt;
SET Elmnt = NULL;
SET ClimbChildren = FALSE;
END IF;
IF ClimbChildren THEN
DECLARE NxtSibl REFERENCE TO inXML;
MOVE NxtSibl FIRSTCHILD;
WHILE LASTMOVE(NxtSibl) DO
DECLARE Child REFERENCE TO NxtSibl;
MOVE NxtSibl NEXTSIBLING;
CALL RemoveEmptyElements(Child);
END WHILE;
END IF;
END;
CREATE PROCEDURE CopyMessageHeaders() BEGIN
DECLARE I INTEGER 1;
DECLARE J INTEGER CARDINALITY(InputRoot.*[]);
WHILE I < J DO
SET OutputRoot.*[I] = InputRoot.*[I];
SET I = I + 1;
END WHILE;
END;
CREATE PROCEDURE CopyEntireMessage() BEGIN
SET OutputRoot = InputRoot;
END;
END MODULE; |
Note the
Code: |
DECLARE OutMsg REFERENCE TO OutputRoot.XML.[1]; |
is what was changed.
What doesn't work is if you send in a message that looks like <A></A>...in this case the message ends up with no body and the MQPut fails. I suppose a check could be done to see if this is the case. Enjoy... |
|
Back to top |
|
 |
|