Reputation: 6258
Assuming I have this XML:
<Level1>
<Level2>
<Level3>
<Level4>
Level 4 Inner Text
</Level4>
</Level3>
</Level2>
</Level1>
But of course, imagine more nodes than a single path of depth...
Using E4X, which I am forced to use through an application called Rhapsody
, I can essentially write a recursive function like so:
function iterateXML(xml) {
log.info(xml.name()); // like console.log
for each (var child in xml.*) { // .* == get all children
iterateXML(child);
}
}
I would (essentially) expect something like this:
Level1
Level2
Level3
Level4
// EXCEPTION... Cuz Level 4 Inner Text was passed in, which doesn't have a .name()
Instead, what I get is this:
Level1
Level2
Level3
// EXCEPTION... Cuz Level 4 Inner Text was passed in, which doesn't have a .name()
What seems to be happening is that, any time a child xml from xml.*
is found to have no descendants, just text, then it completely forgets that node is an XML node, and just returns me the inner text. So I never get to actually SEE the Level4
child XML node, I just get back the inner text.
The same thing happens if the lowest node is Level 2, or level 100. It essentially skips the last one. If the current target is <lowestNode>SomeValue</lowestNode>
, it only gives me SomeValue
.
Similarly, this XML:
<Root>
<Child>
<GrandChild>Value1</GrandChild>
</Child>
<Child>
Value2
</Child>
</Root>
with this code:
function iterateXML(xml) {
for each (var child in xml.*) { // .* == get all children
log.info(child.toString());
}
}
would evaluute to:
<Child><GrandChild>Value1</GrandChild></Child>
Value2
Because the first node has an XML descendant, so it treats it as full XML. But the second one does not have an XML descendant, so it just strips off the XML and gives me the value.
Very inconsistent.
Upvotes: 0
Views: 124
Reputation: 1729
For what it's worth, when I run your first example in the Mozilla Rhino engine, I get the following, so I think you might have been encountering a bug in the Rhapsody implementation.
Level1
Level2
Level3
Level4
null // no exception. Calling .name() on a text node returns null
What you encountered with .toString()
is the documented behavior of that method. When calling .toString()
on an xml node of type element, if the element has simple content then the simple content is returned. Otherwise, the same output as calling the .toXMLString()
method is returned.
Upvotes: 0
Reputation: 6258
I believe there are a lot of intricacies of the old E4X and it is simply difficult to use. But the solution I have found is in a method I stumbled upon. It requires a bit of extra checking and manual code, but no issue:
if (xml.hasSimpleContent()) {
var attributes = xml.@*; //or xml.attributes() if that works
var name = xml.name();
var value = xml.toString(); // unfortunately evaluates to that simpleContent, but I can use that.
}
Seems simple now that I see it, but the inconsistency of toString() threw things off
Upvotes: 0