print all attributes in a xml by recursive method - recursion

The problem is why I can't find any attributes from the rootElement?
my xml is
<?xml version="1.0" encoding="GBK"?>
<AccountInfos>
<!--this is a test for dom4j-->
<AccountInfo1 WebsiteName="ÐÂÀË" Account="123">Account1</AccountInfo1>
<AccountInfo2 WebsiteName="ÍøÒ×" Account="123">Account2</AccountInfo2>
</AccountInfos>
and my code is like this
private void treeWalker(Element element)
{
int size = element.nodeCount();
for (int i = 0; i < size; i++)
{
Node node = element.node(i);
if (node instanceof Element)
{
treeWalker((Element) node);
}
else if(node instanceof Attribute)
{
Attribute attribute=(Attribute)node;
System.out.println(attribute.getName()+":"+attribute.getValue());
}
else
{
continue;
}
}
}
when I debug in this method I can‘t go into the second if block

Attributes are not considered part of the Element (or Branch, actually) content (such as Elements, Comments or Text nodes). You must retrieve then specially, e.g. with an attributeIterator().

Related

ConcurrentModificationException when reinserting a node JavaFX [duplicate]

We all know you can't do the following because of ConcurrentModificationException:
for (Object i : l) {
if (condition(i)) {
l.remove(i);
}
}
But this apparently works sometimes, but not always. Here's some specific code:
public static void main(String[] args) {
Collection<Integer> l = new ArrayList<>();
for (int i = 0; i < 10; ++i) {
l.add(4);
l.add(5);
l.add(6);
}
for (int i : l) {
if (i == 5) {
l.remove(i);
}
}
System.out.println(l);
}
This, of course, results in:
Exception in thread "main" java.util.ConcurrentModificationException
Even though multiple threads aren't doing it. Anyway.
What's the best solution to this problem? How can I remove an item from the collection in a loop without throwing this exception?
I'm also using an arbitrary Collection here, not necessarily an ArrayList, so you can't rely on get.
Iterator.remove() is safe, you can use it like this:
List<String> list = new ArrayList<>();
// This is a clever way to create the iterator and call iterator.hasNext() like
// you would do in a while-loop. It would be the same as doing:
// Iterator<String> iterator = list.iterator();
// while (iterator.hasNext()) {
for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
String string = iterator.next();
if (string.isEmpty()) {
// Remove the current element from the iterator and the list.
iterator.remove();
}
}
Note that Iterator.remove() is the only safe way to modify a collection during iteration; the behavior is unspecified if the underlying collection is modified in any other way while the iteration is in progress.
Source: docs.oracle > The Collection Interface
And similarly, if you have a ListIterator and want to add items, you can use ListIterator#add, for the same reason you can use Iterator#remove — it's designed to allow it.
In your case you tried to remove from a list, but the same restriction applies if trying to put into a Map while iterating its content.
This works:
Iterator<Integer> iter = l.iterator();
while (iter.hasNext()) {
if (iter.next() == 5) {
iter.remove();
}
}
I assumed that since a foreach loop is syntactic sugar for iterating, using an iterator wouldn't help... but it gives you this .remove() functionality.
With Java 8 you can use the new removeIf method. Applied to your example:
Collection<Integer> coll = new ArrayList<>();
//populate
coll.removeIf(i -> i == 5);
Since the question has been already answered i.e. the best way is to use the remove method of the iterator object, I would go into the specifics of the place where the error "java.util.ConcurrentModificationException" is thrown.
Every collection class has a private class which implements the Iterator interface and provides methods like next(), remove() and hasNext().
The code for next looks something like this...
public E next() {
checkForComodification();
try {
E next = get(cursor);
lastRet = cursor++;
return next;
} catch(IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
Here the method checkForComodification is implemented as
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
So, as you can see, if you explicitly try to remove an element from the collection. It results in modCount getting different from expectedModCount, resulting in the exception ConcurrentModificationException.
You can either use the iterator directly like you mentioned, or else keep a second collection and add each item you want to remove to the new collection, then removeAll at the end. This allows you to keep using the type-safety of the for-each loop at the cost of increased memory use and cpu time (shouldn't be a huge problem unless you have really, really big lists or a really old computer)
public static void main(String[] args)
{
Collection<Integer> l = new ArrayList<Integer>();
Collection<Integer> itemsToRemove = new ArrayList<>();
for (int i=0; i < 10; i++) {
l.add(Integer.of(4));
l.add(Integer.of(5));
l.add(Integer.of(6));
}
for (Integer i : l)
{
if (i.intValue() == 5) {
itemsToRemove.add(i);
}
}
l.removeAll(itemsToRemove);
System.out.println(l);
}
In such cases a common trick is (was?) to go backwards:
for(int i = l.size() - 1; i >= 0; i --) {
if (l.get(i) == 5) {
l.remove(i);
}
}
That said, I'm more than happy that you have better ways in Java 8, e.g. removeIf or filter on streams.
Same answer as Claudius with a for loop:
for (Iterator<Object> it = objects.iterator(); it.hasNext();) {
Object object = it.next();
if (test) {
it.remove();
}
}
With Eclipse Collections, the method removeIf defined on MutableCollection will work:
MutableList<Integer> list = Lists.mutable.of(1, 2, 3, 4, 5);
list.removeIf(Predicates.lessThan(3));
Assert.assertEquals(Lists.mutable.of(3, 4, 5), list);
With Java 8 Lambda syntax this can be written as follows:
MutableList<Integer> list = Lists.mutable.of(1, 2, 3, 4, 5);
list.removeIf(Predicates.cast(integer -> integer < 3));
Assert.assertEquals(Lists.mutable.of(3, 4, 5), list);
The call to Predicates.cast() is necessary here because a default removeIf method was added on the java.util.Collection interface in Java 8.
Note: I am a committer for Eclipse Collections.
Make a copy of existing list and iterate over new copy.
for (String str : new ArrayList<String>(listOfStr))
{
listOfStr.remove(/* object reference or index */);
}
People are asserting one can't remove from a Collection being iterated by a foreach loop. I just wanted to point out that is technically incorrect and describe exactly (I know the OP's question is so advanced as to obviate knowing this) the code behind that assumption:
for (TouchableObj obj : untouchedSet) { // <--- This is where ConcurrentModificationException strikes
if (obj.isTouched()) {
untouchedSet.remove(obj);
touchedSt.add(obj);
break; // this is key to avoiding returning to the foreach
}
}
It isn't that you can't remove from the iterated Colletion rather that you can't then continue iteration once you do. Hence the break in the code above.
Apologies if this answer is a somewhat specialist use-case and more suited to the original thread I arrived here from, that one is marked as a duplicate (despite this thread appearing more nuanced) of this and locked.
With a traditional for loop
ArrayList<String> myArray = new ArrayList<>();
for (int i = 0; i < myArray.size(); ) {
String text = myArray.get(i);
if (someCondition(text))
myArray.remove(i);
else
i++;
}
ConcurrentHashMap or ConcurrentLinkedQueue or ConcurrentSkipListMap may be another option, because they will never throw any ConcurrentModificationException, even if you remove or add item.
Another way is to use a copy of your arrayList just for iteration:
List<Object> l = ...
List<Object> iterationList = ImmutableList.copyOf(l);
for (Object curr : iterationList) {
if (condition(curr)) {
l.remove(curr);
}
}
A ListIterator allows you to add or remove items in the list. Suppose you have a list of Car objects:
List<Car> cars = ArrayList<>();
// add cars here...
for (ListIterator<Car> carIterator = cars.listIterator(); carIterator.hasNext(); )
{
if (<some-condition>)
{
carIterator().remove()
}
else if (<some-other-condition>)
{
carIterator().add(aNewCar);
}
}
Now, You can remove with the following code
l.removeIf(current -> current == 5);
I know this question is too old to be about Java 8, but for those using Java 8 you can easily use removeIf():
Collection<Integer> l = new ArrayList<Integer>();
for (int i=0; i < 10; ++i) {
l.add(new Integer(4));
l.add(new Integer(5));
l.add(new Integer(6));
}
l.removeIf(i -> i.intValue() == 5);
Java Concurrent Modification Exception
Single thread
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String value = iter.next()
if (value == "A") {
list.remove(it.next()); //throws ConcurrentModificationException
}
}
Solution: iterator remove() method
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String value = iter.next()
if (value == "A") {
it.remove()
}
}
Multi thread
copy/convert and iterate over another one collection. For small collections
synchronize[About]
thread safe collection[About]
I have a suggestion for the problem above. No need of secondary list or any extra time. Please find an example which would do the same stuff but in a different way.
//"list" is ArrayList<Object>
//"state" is some boolean variable, which when set to true, Object will be removed from the list
int index = 0;
while(index < list.size()) {
Object r = list.get(index);
if( state ) {
list.remove(index);
index = 0;
continue;
}
index += 1;
}
This would avoid the Concurrency Exception.
for (Integer i : l)
{
if (i.intValue() == 5){
itemsToRemove.add(i);
break;
}
}
The catch is the after removing the element from the list if you skip the internal iterator.next() call. it still works! Though I dont propose to write code like this it helps to understand the concept behind it :-)
Cheers!
Example of thread safe collection modification:
public class Example {
private final List<String> queue = Collections.synchronizedList(new ArrayList<String>());
public void removeFromQueue() {
synchronized (queue) {
Iterator<String> iterator = queue.iterator();
String string = iterator.next();
if (string.isEmpty()) {
iterator.remove();
}
}
}
}
I know this question assumes just a Collection, and not more specifically any List. But for those reading this question who are indeed working with a List reference, you can avoid ConcurrentModificationException with a while-loop (while modifying within it) instead if you want to avoid Iterator (either if you want to avoid it in general, or avoid it specifically to achieve a looping order different from start-to-end stopping at each element [which I believe is the only order Iterator itself can do]):
*Update: See comments below that clarify the analogous is also achievable with the traditional-for-loop.
final List<Integer> list = new ArrayList<>();
for(int i = 0; i < 10; ++i){
list.add(i);
}
int i = 1;
while(i < list.size()){
if(list.get(i) % 2 == 0){
list.remove(i++);
} else {
i += 2;
}
}
No ConcurrentModificationException from that code.
There we see looping not start at the beginning, and not stop at every element (which I believe Iterator itself can't do).
FWIW we also see get being called on list, which could not be done if its reference was just Collection (instead of the more specific List-type of Collection) - List interface includes get, but Collection interface does not. If not for that difference, then the list reference could instead be a Collection [and therefore technically this Answer would then be a direct Answer, instead of a tangential Answer].
FWIWW same code still works after modified to start at beginning at stop at every element (just like Iterator order):
final List<Integer> list = new ArrayList<>();
for(int i = 0; i < 10; ++i){
list.add(i);
}
int i = 0;
while(i < list.size()){
if(list.get(i) % 2 == 0){
list.remove(i);
} else {
++i;
}
}
One solution could be to rotate the list and remove the first element to avoid the ConcurrentModificationException or IndexOutOfBoundsException
int n = list.size();
for(int j=0;j<n;j++){
//you can also put a condition before remove
list.remove(0);
Collections.rotate(list, 1);
}
Collections.rotate(list, -1);
Try this one (removes all elements in the list that equal i):
for (Object i : l) {
if (condition(i)) {
l = (l.stream().filter((a) -> a != i)).collect(Collectors.toList());
}
}
You can use a while loop.
Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
while(iterator.hasNext()){
Map.Entry<String, String> entry = iterator.next();
if(entry.getKey().equals("test")) {
iterator.remove();
}
}
I ended up with this ConcurrentModificationException, while iterating the list using stream().map() method. However the for(:) did not throw the exception while iterating and modifying the the list.
Here is code snippet , if its of help to anyone:
here I'm iterating on a ArrayList<BuildEntity> , and modifying it using the list.remove(obj)
for(BuildEntity build : uniqueBuildEntities){
if(build!=null){
if(isBuildCrashedWithErrors(build)){
log.info("The following build crashed with errors , will not be persisted -> \n{}"
,build.getBuildUrl());
uniqueBuildEntities.remove(build);
if (uniqueBuildEntities.isEmpty()) return EMPTY_LIST;
}
}
}
if(uniqueBuildEntities.size()>0) {
dbEntries.addAll(uniqueBuildEntities);
}
If using HashMap, in newer versions of Java (8+) you can select each of 3 options:
public class UserProfileEntity {
private String Code;
private String mobileNumber;
private LocalDateTime inputDT;
// getters and setters here
}
HashMap<String, UserProfileEntity> upMap = new HashMap<>();
// remove by value
upMap.values().removeIf(value -> !value.getCode().contains("0005"));
// remove by key
upMap.keySet().removeIf(key -> key.contentEquals("testUser"));
// remove by entry / key + value
upMap.entrySet().removeIf(entry -> (entry.getKey().endsWith("admin") || entry.getValue().getInputDT().isBefore(LocalDateTime.now().minusMinutes(3)));
The best way (recommended) is use of java.util.concurrent package. By
using this package you can easily avoid this exception. Refer
Modified Code:
public static void main(String[] args) {
Collection<Integer> l = new CopyOnWriteArrayList<Integer>();
for (int i=0; i < 10; ++i) {
l.add(new Integer(4));
l.add(new Integer(5));
l.add(new Integer(6));
}
for (Integer i : l) {
if (i.intValue() == 5) {
l.remove(i);
}
}
System.out.println(l);
}
Iterators are not always helpful when another thread also modifies the collection. I had tried many ways but then realized traversing the collection manually is much safer (backward for removal):
for (i in myList.size-1 downTo 0) {
myList.getOrNull(i)?.also {
if (it == 5)
myList.remove(it)
}
}
In case ArrayList:remove(int index)- if(index is last element's position) it avoids without System.arraycopy() and takes not time for this.
arraycopy time increases if(index decreases), by the way elements of list also decreases!
the best effective remove way is- removing its elements in descending order:
while(list.size()>0)list.remove(list.size()-1);//takes O(1)
while(list.size()>0)list.remove(0);//takes O(factorial(n))
//region prepare data
ArrayList<Integer> ints = new ArrayList<Integer>();
ArrayList<Integer> toRemove = new ArrayList<Integer>();
Random rdm = new Random();
long millis;
for (int i = 0; i < 100000; i++) {
Integer integer = rdm.nextInt();
ints.add(integer);
}
ArrayList<Integer> intsForIndex = new ArrayList<Integer>(ints);
ArrayList<Integer> intsDescIndex = new ArrayList<Integer>(ints);
ArrayList<Integer> intsIterator = new ArrayList<Integer>(ints);
//endregion
// region for index
millis = System.currentTimeMillis();
for (int i = 0; i < intsForIndex.size(); i++)
if (intsForIndex.get(i) % 2 == 0) intsForIndex.remove(i--);
System.out.println(System.currentTimeMillis() - millis);
// endregion
// region for index desc
millis = System.currentTimeMillis();
for (int i = intsDescIndex.size() - 1; i >= 0; i--)
if (intsDescIndex.get(i) % 2 == 0) intsDescIndex.remove(i);
System.out.println(System.currentTimeMillis() - millis);
//endregion
// region iterator
millis = System.currentTimeMillis();
for (Iterator<Integer> iterator = intsIterator.iterator(); iterator.hasNext(); )
if (iterator.next() % 2 == 0) iterator.remove();
System.out.println(System.currentTimeMillis() - millis);
//endregion
for index loop: 1090 msec
for desc index: 519 msec---the best
for iterator: 1043 msec
you can also use Recursion
Recursion in java is a process in which a method calls itself continuously. A method in java that calls itself is called recursive method.

JavaFx Treeview reorder items by drag-and-drop

I have a treeview of hierarchical data that represents elements retrieved from a database. I would like to be able to move child (leaf) nodes from one parent to another and rearrange the sequence of leaf nodes within a parent via drag-and-drop, finally updating the database with the results of the move operations.
Right now I can drop one of the leaf nodes onto a parent node which allows me to add the child to the parent. However, I don't really see how to drop a leaf node between two other leaf nodes, either in the same parent or in a different parent node.
I would like to be able to do something like the following. Starting with a tree that looks like this:
Root
|
+-+-P1
| |
| +--L1a
| +--L1b
|
+-+-P2
|
+--L2a
+--L2b
For example, I would like to be able to select L2a and drag it up and drop it between L1a and L1b. Or before L1a, or after L1b. Having done that I would like to drag the child nodes of P1 around and rearrange them via DND.
Part of this would be to provide an indication of the drop location. For example, a line between L1a and L1b if you have the cursor positioned 'between' these nodes.
Is this possible? I don't see any examples of this anywhere.
One other thing I am seeing is that the effect of DND doesn't remove the leaf node from its original location even though in the setOnDragDetected method call for my cells I call cell.startDragAndDrop(TransferMode.MOVE). How can I get that to work?
Edit 9/1/17
I figured out the last part of not removing the leaf node.
Here is the code I am using to test this process out. I have an interface IStoryItem that is the (empty) interface implemented by two subclasses, Story and Part (just to create a hierarchy to test with). The Story class has title (String) and parts (Part[]) fields. The Part class has title (String) and partNumber (int) fields. I have a Utils class that creates an array of Story objects to populate my TreeView instance.
Here is my controller class. It's a bit long and in need of cleanup but shows what I have tried so far.
public class Controller {
public TreeView<IStoryItem> tv;
private final DataFormat objectDataFormat = new DataFormat("application/x-java-serialized-object");
class StoryRoot implements IStoryItem { }
TreeItem<IStoryItem> rootItem;
#FXML
public void initialize() {
StoryRoot storyRoot = new StoryRoot();
rootItem = new TreeItem<>(storyRoot);
tv.setRoot(rootItem);
// For Drag and Drop:
// - rootItem can only accept Story nodes.
// - Story nodes can only accept Part nodes.
// - Part nodes can't accept any other nodes.
tv.setCellFactory(new Callback<TreeView<IStoryItem>, TreeCell<IStoryItem>>() {
#Override
public TreeCell<IStoryItem> call(TreeView<IStoryItem> siTreeView) {
TreeCell<IStoryItem> cell = new TreeCell<IStoryItem>() {
#Override
protected void updateItem(IStoryItem item, boolean empty) {
super.updateItem(item, empty);
if (item != null) { setText(item.toString()); }
}
};
// The following calls are as outlined in:
// https://docs.oracle.com/javase/8/javafx/events-tutorial/drag-drop.htm#CHDJFJDH
cell.setOnDragDetected((MouseEvent event) -> {
// Don't drag Story nodes.
if (cell.getItem() instanceof Story) return;
// drag was detected, start a drag-and-drop gesture
// allow Move transfer mode only
Dragboard db = cell.startDragAndDrop(TransferMode.MOVE);
// Put the Part on the dragboard
// From: https://stackoverflow.com/a/30916660/780350
ClipboardContent content = new ClipboardContent();
content.put(objectDataFormat, cell.getItem());
db.setContent(content);
event.consume();
});
cell.setOnDragDropped((DragEvent event) -> {
try {
Dragboard db = event.getDragboard();
boolean success = false;
if (db.hasContent(objectDataFormat)) {
Part droppedPart = (Part)db.getContent(objectDataFormat);
IStoryItem targetStoryItem = cell.getItem();
// Question: How to handle drops between leaf items or
// before the initial leaf or after the final leaf.
if (targetStoryItem instanceof Story) {
Story story = (Story) targetStoryItem;
updateStoryWith(droppedPart, story);
addPartTo(cell.getTreeItem(), droppedPart);
success = true;
}
}
event.setDropCompleted(success);
event.consume();
} catch (Exception e) {
System.out.println(e.getMessage());
}
});
cell.setOnDragDone((DragEvent event) -> {
/*
* the drag and drop gesture ended
* if the data was successfully moved, clear it
*/
if (event.getTransferMode() == TransferMode.MOVE) {
// TODO: remove the part that got moved.
IStoryItem item = cell.getItem();
TreeItem<IStoryItem> ti = cell.getTreeItem();
TreeItem<IStoryItem> pti = ti.getParent();
pti.getChildren().remove(ti);
IStoryItem psi = pti.getValue();
boolean removed = removePartFrom(psi, item);
}
event.consume();
});
return cell;
};
});
tv.getSelectionModel()
.selectedItemProperty()
.addListener((observable, oldValue, newValue) -> inspectObject(newValue.getValue()));;
Story[] stories = Utils.createStories();
for (Story s: stories) {
addStoryToTree(s);
}
}
private void updateStoryWith(Part droppedPart, Story story) {
List<Part> partsList = new ArrayList<>(Arrays.asList(story.parts));
partsList.add(droppedPart);
Part [] newParts = (Part[])partsList.toArray(new Part[partsList.size()]);
int idx = 1;
for (Part part : newParts) {
part.partnumber = idx++;
}
story.parts = newParts;
}
private void inspectObject(Object o) {
if (!(o instanceof IStoryItem)) {
System.out.println(o.getClass().toString());
} else if (o instanceof Story) {
Story s = (Story)o;
System.out.println("Story: " + s.toString());
} else if (o instanceof Part) {
Part s = (Part)o;
System.out.println("Part: " + s.toString());
}
}
void addStoryToTree(Story story) {
if (story.parts.length == 0) return;
TreeItem<IStoryItem> item = new TreeItem<>(story);
rootItem.getChildren().add(item);
for (Part part : story.parts) {
addPartTo(item, part);
}
}
void addPartTo(TreeItem<IStoryItem> storyItem, Part part) {
TreeItem<IStoryItem> partItem = new TreeItem<>(part);
storyItem.getChildren().add(partItem);
}
boolean removePartFrom(IStoryItem si, IStoryItem pi) {
if (!(si instanceof Story)) return false;
if (!(pi instanceof Part)) return false;
Story story = (Story) si;
Part part = (Part) pi;
List<Part> plist = new LinkedList<>(Arrays.asList(story.parts));
if (!plist.contains(part)) return false;
boolean removed = plist.remove(part);
story.parts = plist.toArray(new Part[plist.size()]);
return removed;
}
}

Using MvcSiteMap how do I create links to next and previous nodes?

I'd like to implement something like the following HTML helpers in MvcSiteMapProvider:
Html.MvcSiteMap().Previous()
Html.MvcSiteMap().Next()
However, I am quite new to their API, is it possible to do that, and if so, how?
You can accomplish this by building custom HTML helpers. I have answered this question already at GitHub and provided a working demo project, but I am copying here for reference.
The logic to walk up and down the document would look something like this, the rest of the code is for the most part boilerplate templated HTML helper code.
private static ISiteMapNode GetNextNode(ISiteMapNode startingNode, IDictionary<string, object> sourceMetadata)
{
ISiteMapNode nextNode = null;
if (startingNode.HasChildNodes)
{
// Get the first child node
nextNode = startingNode.ChildNodes[0];
}
else if (startingNode.ParentNode != null)
{
// Get the next sibling node
nextNode = startingNode.NextSibling;
if (nextNode == null)
{
// If there are no more siblings, the next position
// should be the parent's next sibling
var parent = startingNode.ParentNode;
if (parent != null)
{
nextNode = parent.NextSibling;
}
}
}
// If the node is not visible or accessible, run the operation recursively until a visible node is found
if (nextNode != null && !(nextNode.IsVisible(sourceMetadata) || nextNode.IsAccessibleToUser()))
{
nextNode = GetNextNode(nextNode, sourceMetadata);
}
return nextNode;
}
private static ISiteMapNode GetPreviousNode(ISiteMapNode startingNode, IDictionary<string, object> sourceMetadata)
{
ISiteMapNode previousNode = null;
// Get the previous sibling
var previousSibling = startingNode.PreviousSibling;
if (previousSibling != null)
{
// If there are any children, go to the last descendant
if (previousSibling.HasChildNodes)
{
previousNode = previousSibling.Descendants.Last();
}
else
{
// If there are no children, return the sibling.
previousNode = previousSibling;
}
}
else
{
// If there are no more siblings before this one, go to the parent node
previousNode = startingNode.ParentNode;
}
// If the node is not visible or accessible, run the operation recursively until a visible node is found
if (previousNode != null && !(previousNode.IsVisible(sourceMetadata) || previousNode.IsAccessibleToUser()))
{
previousNode = GetPreviousNode(previousNode, sourceMetadata);
}
return previousNode;
}

JavaCC AST representation

I am using JavaCC to generate a parser and one method is to accept 4 + 5 for example which works well.
However now I need to modify this so that it prints PlusNode(IntegerLiteral(4) , IntegerLiteral(5))
I modified some code for this however it is printing :
(ExprNode(IntegerLiteral(4),PlusNode,IntegerLiteral(5),),)
since the rule is
INTLITERAL PLUS INTLITERAL
My dump method in SimpleNode is:
public void dump(String prefix) {
System.out.print(toString(prefix));
if (children != null) {
System.out.print("(");
for (int i = 0; i < children.length; ++i) {
SimpleNode n = (SimpleNode)children[i];
if (n != null) {
n.dump(prefix +"");
}System.out.print(",");
}
System.out.print(")");
}
}
How can I get the plus before and remove the ,,, in the last part?

How to access children of children recursively?

I have a Canvas which has many components inside it and those again, have many components inside them.
getChildren() returns only the top level children. What is the best way to retrieve all the children (children of children of children and so on).
Well, I sorta know how to do this by iterating through the children, but the code is really messy. I'd prefer to use a nice recursive function. Has anyone written this before? Or is there a Util class to do this?
private function recuse(display : DisplayObjectContainer) : void {
if(display) {
for (var i : int = 0;i < _display.numChildren;i++) {
var child : DisplayObject = display.getChildAt(i);
trace(child.name);
if(child is DisplayObjectContainer) {
recuse(DisplayObjectContainer(child));
}
}
}
}
Try something likely (note you can return the lists recursively if you want to gather all the references to the top level iteration)
function inspect(object:DisplayObject):void
{
if(object is DisplayObjectContainer)
{
var casted:DisplayObjectContainer = object as DisplayObjectContainer
trace("DisplayObjectContainer ", casted.name)
for(var depth:int = 0; depth < casted.numChildren;depth++)
{
inspect(casted.getChildAt(depth))
}
}else{
trace("DisplayObject", object.name );
}
}
inspect(this)
function theCallbackFunction(obj:DisplayObject):void
{
trace(obj.name);
}
//Visit the children first.
//Deep most objects will be visited first and so on.
//stage is visited at the end.
//Uses recursion
function depthFirst(obj:DisplayObject, func:Function):void
{
if(!(obj instanceof DisplayObjectContainer))
{
func(obj);
return;
}
var p:DisplayObjectContainer = DisplayObjectContainer(obj);
var len:Number = p.numChildren;
for(var i:Number = 0; i < len; i++)
{
var child:DisplayObject = p.getChildAt(i);
depthFirst(child, func);
}
func(obj);
}
//Visit the siblings first.
//stage is visited first, then its children, then the grand children and so on
//No recursion.
function breadthFirst(obj:DisplayObject, func:Function):void
{
var q:Array = [];
q.push(obj);
var p:DisplayObjectContainer;
var i:Number, len:Number;
while(q.length != 0)
{
var child:DisplayObject = queue.shift();
func(child);
if(!(child instanceof DisplayObjectContainer))
continue;
p = DisplayObjectContainer(child);
len = p.numChildren;
for(i = 0; i < len; i++)
q.push(p.getChildAt(i));
}
}
depthFirst(this.stage, theCallbackFunction);
breadthFirst(this.stage, theCallbackFunction);

Resources