Author |
Message
|
yazzam |
Posted: Tue Feb 14, 2012 3:54 am Post subject: Impossible to know if an xml field is empty |
|
|
Newbie
Joined: 14 Feb 2012 Posts: 4
|
Hi,
Here is the situation:
I have an XML tree. I want to remove from it all the empty nodes dinamically.
Code: |
<Flux>
<a>
<b><c/></b>
<d/>
</a>
</Flux> |
Every thing works fine on the first itteration, and the node <c/> is deleted.
After the suppression of <c/> when the tree become like this:
Code: |
<Flux>
<a><b/><d/></a>
</Flux> |
I want to delete the node <b/>
The problem is that I haven't find a way to know that this nod is empty
Here is an example code (without the dinamic part)
Code: |
SET OutputRoot = InputRoot;
DECLARE cursor REFERENCE TO OutputRoot.XMLNSC.Flux;
MOVE cursor to OutputRoot.XMLNSC.Flux.a.b.c;
IF FIELDVALUE(cursor) = '' THEN
SET Environment.Variables.cEmpty = 'true';
DELETE FIELD cursor;
END IF;
MOVE cursor to OutputRoot.XMLNSC.Flux.a.b;
SET Environment.Variables.bName = FIELDNAME(cursor);
SET Environment.Variables.bVal = FIELDVALUE(cursor);
SET Environment.Variables.b = cursor;
SET Environment.Variables.Root = OutputRoot.XMLNSC;
IF FIELDVALUE(cursor) = '' OR FIELDVALUE(cursor) = NULL OR cursor = NULL THEN
SET Environment.Variables.bbbVide = 'true';
DELETE FIELD cursor;
END IF;
|
Adn her is the trace:
Code: |
( ['MQROOT' : 0x116a1b410]
(0x01000000:Name):Variables = (
(0x03000000:NameValue):cEmpty = 'true' (CHARACTER)
(0x03000000:NameValue):bName = 'b' (CHARACTER)
(0x01000000:Name ):b =
(0x01000000:Name ):Root = (
(0x01000000:Name):XmlDeclaration = (
(0x03000000:NameValue):Version = '1.0' (CHARACTER)
(0x03000000:NameValue):Encoding = 'ISO-8859-1' (CHARACTER)
)
(0x01000000:Name):Flux = (
(0x01000000:Name):a = (
(0x01000000:Name):b =
(0x01000000:Name):d =
)
)
)
)
)
|
the node </c> is detected as empty by the test
Code: |
MOVE cursor to OutputRoot.XMLNSC.Flux.a.b.c;
IF FIELDVALUE(cursor) = '' |
but the same test on <b>
Code: |
MOVE cursor to OutputRoot.XMLNSC.Flux.a.b;
IF FIELDVALUE(cursor) = '' OR FIELDVALUE(cursor) = NULL OR cursor = NULL |
Doesn't detect that the node is empty.
Does any body see a solution ?
Thank you |
|
Back to top |
|
 |
rekarm01 |
Posted: Tue Feb 14, 2012 4:02 am Post subject: Re: Impossible to know if an xml field is empty |
|
|
Grand Master
Joined: 25 Jun 2008 Posts: 1415
|
yazzam wrote: |
Code: |
MOVE cursor to OutputRoot.XMLNSC.Flux.a.b;
IF FIELDVALUE(cursor) = '' OR FIELDVALUE(cursor) = NULL OR cursor = NULL |
|
Use the LASTMOVE() function to determine whether the cursor reference is valid. Use the IS operator to test for NULL. |
|
Back to top |
|
 |
yazzam |
Posted: Tue Feb 14, 2012 5:17 am Post subject: |
|
|
Newbie
Joined: 14 Feb 2012 Posts: 4
|
Hi rekarm01,
Thank you for your answer.
I changed my code like this
Code: |
MOVE cursor to OutputRoot.XMLNSC.Flux.a.b;
SET Environment.Variables.bLastMove = LASTMOVE(cursor);
IF FIELDVALUE(cursor) IS NULL THEN
SET Environment.Variables.bEmpty = 'true';
DELETE FIELD cursor;
END IF;
|
the trace is now:
Code: |
(0x03000000:NameValue):bLastMove = TRUE (BOOLEAN)
(0x03000000:NameValue):bEmpty = 'true' (CHARACTER)
|
So it's the result thant I need.
The problem is now that if I do the same test on a non empty node like <a> (<a> has children) the result is the same
Code:
Code: |
MOVE cursor to OutputRoot.XMLNSC.Flux.a;
SET Environment.Variables.aLastMove = LASTMOVE(cursor);
IF FIELDVALUE(cursor) IS NULL THEN
SET Environment.Variables.aEmpty = 'true';
END IF;
|
The trace is
Code: |
(0x03000000:NameValue):aLastMove = TRUE (BOOLEAN)
(0x03000000:NameValue):aEmpty = 'true' (CHARACTER)
|
It means that the FIELDVALUE of a node that have children is null as the FIELDVALUE of my node <b/> that became empty after the deleting of the node <c/>.
So I still can't detect that <b/> is empty.
The solution I think is to test that <b/> is null and has no children.
I'm going to test it |
|
Back to top |
|
 |
kimbert |
Posted: Tue Feb 14, 2012 5:33 am Post subject: |
|
|
 Jedi Council
Joined: 29 Jul 2003 Posts: 5542 Location: Southampton
|
So you want to end up with a tree that contains no empty tags?
Currently you are walking the tree multiple times - that will be inefficient. A better approach would be something like this:
Code: |
For each child of the root element
zeroLength=true
IF the current element has children
For each child of the current element
IF the child has a non-zero length,
set zeroLength=false
ELSE
IF the current element has a non-zero length
set zeroLength=false
IF (zeroLength=true)
delete this node |
It's not quite as easy as that, because you need to be careful not to delete the node that you are positioned on. And you probably want a procedure that returns 0 or 1 depending on whether the node is zero-length, regardless of whether it has children. Then you can call that recursively.
But you get the idea - it's possible to do the job in a single pass over the tree. |
|
Back to top |
|
 |
mqsiuser |
Posted: Tue Feb 14, 2012 5:34 am Post subject: |
|
|
 Yatiri
Joined: 15 Apr 2008 Posts: 637 Location: Germany
|
rekarm01 already gave you great tips!
Instead of checking for NULL with "field = NULL" you need to use "field IS NULL".
Also to check if a field exists move into it and check if the lastmove worked.
Or move into children and check if that worked, if you want to know whether a node has children.
To check the field value for NULL is strange: "FIELDVALUE(cursor) IS NULL" _________________ Just use REFERENCEs
Last edited by mqsiuser on Tue Feb 14, 2012 5:35 am; edited 1 time in total |
|
Back to top |
|
 |
mqjeff |
Posted: Tue Feb 14, 2012 5:34 am Post subject: |
|
|
Grand Master
Joined: 25 Jun 2008 Posts: 17447
|
One generally does not expect that an xml element that has children will also have a value.
You can use LASTMOVE to check to see if you have succeeded in moving to the first child. |
|
Back to top |
|
 |
yazzam |
Posted: Tue Feb 14, 2012 5:41 am Post subject: |
|
|
Newbie
Joined: 14 Feb 2012 Posts: 4
|
Thank you all for your replies, I finnaly found a satisfiying test.
Code: |
MOVE cursor to OutputRoot.XMLNSC.Flux.a;
SET Environment.Variables.aLastMove = LASTMOVE(cursor);
IF FIELDVALUE(cursor) IS NULL AND CARDINALITY(cursor.*[]) = 0 THEN
SET Environment.Variables.aEmpty = 'true';
ELSE
SET Environment.Variables.aEmpty = 'false';
END IF;
|
This test return false for nodes with value and nodes with children.
It returns true for empty nodes.
I jsut find verry strange that the test IF FIELDVALUE(cursor) = '' works for <c>
Code: |
<Flux>
<a>
<b><c/></b>
<d/>
</a>
</Flux>
|
but don't work for <b> after deleting <c>
Code: |
<Flux>
<a>
<b></b>
<d/>
</a>
</Flux>
|
|
|
Back to top |
|
 |
adubya |
Posted: Tue Feb 14, 2012 5:43 am Post subject: |
|
|
Partisan
Joined: 25 Aug 2011 Posts: 377 Location: GU12, UK
|
FIELDVALUE examines element content not the presence of child elements. |
|
Back to top |
|
 |
kimbert |
Posted: Tue Feb 14, 2012 5:56 am Post subject: |
|
|
 Jedi Council
Joined: 29 Jul 2003 Posts: 5542 Location: Southampton
|
Quote: |
CARDINALITY(cursor.*[]) = 0 |
...could be slow if the cursor is positioned on something with a lot of child elements.
Better to try to move the cursor ( or a copy of it if you prefer ) to the first child, and remember whether the move succeeded. You will get the same answer a lot more efficiently. |
|
Back to top |
|
 |
yazzam |
Posted: Tue Feb 14, 2012 6:01 am Post subject: |
|
|
Newbie
Joined: 14 Feb 2012 Posts: 4
|
[/quote]
FIELDVALUE examines element content not the presence of child elements.
Quote: |
Yes it's exacltly what I want to do the problem is that for two nodes with the same characteristic the result is different |
|
|
Back to top |
|
 |
mqjeff |
Posted: Tue Feb 14, 2012 6:15 am Post subject: |
|
|
Grand Master
Joined: 25 Jun 2008 Posts: 17447
|
yazzam wrote: |
Yes it's exacltly what I want to do the problem is that for two nodes with the same characteristic the result is different |
You haven't explained how you have managed to delete your <c/> element, and shown that this has ensure that the <b> element actually has no value.
What I mean is that very strictly according to the XML standard, the following
has no value, but
DOES have a value.
And, again, FIELDVALUE only tests the value of the element. |
|
Back to top |
|
 |
kimbert |
Posted: Tue Feb 14, 2012 6:33 am Post subject: |
|
|
 Jedi Council
Joined: 29 Jul 2003 Posts: 5542 Location: Southampton
|
Quote: |
FIELDVALUE examines element content |
True.
Quote: |
not the presence of child elements |
Not quite true. If there are child elements of type 'Value' ( i.e. nodes with a value and no name ) then the text values of all such nodes will be concatenated together and returned as the value of the parent. You can get this situation when the content of an element is a CDATA section followed by some white space.
But that doesn't change your point very much. yazzam needs two separate algorithms:
a) determine whether the current element has a text value. FIELDVALUE does this.
b) determine whether the current element has any Name or NameValue child elements, so that he knows whether to recursively walk into the element. MOVE FIRSTCHILD does this, but remember that the child nodes might all be Value nodes, as described above, in which case the element has no *real* children.
Note that it is possible for an XML element to have both children AND a value. The value is then called 'mixed content'. By default the XMLNSC parser throws away mixed content so this will probably not be a problem for you.
Feel free to post your code when you're done. We can check it over for you, and then it will be available to other readers of this thread. |
|
Back to top |
|
 |
fjb_saper |
Posted: Tue Feb 14, 2012 8:01 am Post subject: |
|
|
 Grand High Poobah
Joined: 18 Nov 2003 Posts: 20756 Location: LI,NY
|
And don't forget the particular case where a child does exist:
<a xsi:nil="true"/>
 _________________ MQ & Broker admin |
|
Back to top |
|
 |
kimbert |
Posted: Tue Feb 14, 2012 1:09 pm Post subject: |
|
|
 Jedi Council
Joined: 29 Jul 2003 Posts: 5542 Location: Southampton
|
fjb_saper is correct. It's not just xsi:nil either. What about namespace declarations? Is a tag 'empty' if it only contains namespace declarations? ( I think 'yes' ).
This highlights something that I was going to mention earlier; the requirement is difficult to implement whether you're using ESQL, XSLT or any other transformation language. It's easier to get it wrong than to get it right. So I would be interested to know why the receiving application needs these empty elements to be removed. |
|
Back to top |
|
 |
mqsiuser |
Posted: Tue Feb 14, 2012 8:07 pm Post subject: |
|
|
 Yatiri
Joined: 15 Apr 2008 Posts: 637 Location: Germany
|
kimbert wrote: |
It's not just xsi:nil either. What about namespace declarations? Is a tag 'empty' if it only contains namespace declarations? ( I think 'yes' ). |
@fjb_saper: You are certainly aware of this, but I just like to state that you are talking about xml schema (xsd) definitions now and not (payload) xml. Though this could be, it likely is not the case for xml messages passing through.
@kimbert: Also note that the xml of the OP contains no namespaces (ok, if it would you'd have to consider this, ofc - but everything you don't use relieves you in that case). @OP: If you only have (your payload) XML, then there are only 2 types of children: elements & attributes. Well there is also content and probably it is mixed with elements ... but not in broker, because the parser takes care, afaiu, etc... ... but most notably: You are not having this in your xml (and nothing like that defined in your xsd ... that you probably have and ofc. validates). The OP's XML is elements only! A good decision for simplicities sake! ELSE there needs to be a decision what empty means: Contains no elements, but attributes are ok (choice 1), both not (choice 2) or both not but ignore some (e.g. xsd metadata attributes, e.g. namespace-prefixes) (choice 3). All of which the OP has gone rid off by using elements only!
kimbert wrote: |
This highlights something that I was going to mention earlier; the requirement is difficult to implement whether you're using ESQL, XSLT or any other transformation language. It's easier to get it wrong than to get it right. So I would be interested to know why the receiving application needs these empty elements to be removed. |
Question whether you need your requirement, but there certainly are (legacy) systems that stumble over stuff like that. @OP: your message is simple (no xml-attributes, no namespaces, no schema linked in, no metadata, no other weired stuff!), so that should be easy/doable in custom code (just to re-motivate you with your original idea)!
Be aware you are just programming some custom transformation code which relies on a certain (simple) in-xml-structure to realize custom requirements on the out-xml. Probably there can be some mini-utility functions ( e.g. hasChild(...), fieldExists(...) ), but probably no single function (that you'd possibly reuse later).
Probably the question is whether there always needs to be a custom (code) solution (ok and how well you get that to work&maintain) or if there can be a more generic function, which probably is not worth the hussel.
And: With ESQL (and Java) you have a real programming language. XSLT is much different and when you use it you are happy the first 80%, but then find out 15% is difficult/hard to do and (when your project deadline comes) that you can't do the last 5% at all. Not to mention performance degradation. I cannot understand why you just put ESQL and other technology, esp. XSLT on the same level. _________________ Just use REFERENCEs |
|
Back to top |
|
 |
|