Java: Effizienteste Methode, um alle Elemente in einem org.w3c.dom.Document zu durchlaufen?

Lesezeit: 4 Minuten

Benutzer-Avatar
KJW

Was ist der effizienteste Weg, um alle DOM-Elemente in Java zu durchlaufen?

So etwas aber für jedes einzelne DOM-Element auf Strom org.w3c.dom.Document?

for(Node childNode = node.getFirstChild(); childNode!=null;){
    Node nextChild = childNode.getNextSibling();
    // Do something with childNode, including move or delete...
    childNode = nextChild;
}

  • Rekursiver Aufruf von Node.getChildNodes? download.oracle.com/javase/6/docs/api/org/w3c/dom/…

    – Vance Maverick

    22. März 2011 um 5:38 Uhr

  • Ich finde es interessant, dass die Frage gestellt wurde höchsteffizient Methode zum Iterieren über alle Elemente von a Documentaber keine der Antworten führte Effizienztests durch, und die einzige Erwähnung der Effizienz war “Ich denke” oder ähnliche Vermutungen.

    – Garret Wilson

    14. März 2020 um 20:21 Uhr

Benutzer-Avatar
Javana

Grundsätzlich haben Sie zwei Möglichkeiten, über alle Elemente zu iterieren:

1. Rekursion verwenden (die gebräuchlichste Art, denke ich):

public static void main(String[] args) throws SAXException, IOException,
        ParserConfigurationException, TransformerException {

    DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory
        .newInstance();
    DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
    Document document = docBuilder.parse(new File("document.xml"));
    doSomething(document.getDocumentElement());
}

public static void doSomething(Node node) {
    // do something with the current node instead of System.out
    System.out.println(node.getNodeName());

    NodeList nodeList = node.getChildNodes();
    for (int i = 0; i < nodeList.getLength(); i++) {
        Node currentNode = nodeList.item(i);
        if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
            //calls this method for all the children which is Element
            doSomething(currentNode);
        }
    }
}

2. Rekursion vermeiden verwenden getElementsByTagName() Methode mit * als Parameter:

public static void main(String[] args) throws SAXException, IOException,
        ParserConfigurationException, TransformerException {

    DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory
            .newInstance();
    DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
    Document document = docBuilder.parse(new File("document.xml"));

    NodeList nodeList = document.getElementsByTagName("*");
    for (int i = 0; i < nodeList.getLength(); i++) {
        Node node = nodeList.item(i);
        if (node.getNodeType() == Node.ELEMENT_NODE) {
            // do something with the current element
            System.out.println(node.getNodeName());
        }
    }
}

Ich denke, diese Wege sind beide effizient.
Hoffe das hilft.

  • Indem Sie den Iterationsindex als Argument an die rekursive Funktion übergeben, können Sie sie tail-rekursiv machen, was vom Compiler optimiert wird, um einen Stapelüberlauf zu vermeiden.

    – Chatschik

    3. April 2011 um 18:30 Uhr

  • Ich denke, es ist zu spät, um einen Stapelüberlauf zu vermeiden. Du bist schon hier.

    – Braden

    28. September 2012 um 17:19 Uhr

  • Was lässt Sie glauben, dass die Erstellung einer Knotenliste für das gesamte Dokument effizient ist? Dies bedeutet, dass fast das gesamte Dokument kopiert wird. Oder ist da eine Art verzögerte Auswertung versteckt NodeList Optimierung sequentieller Aufrufe zu item?

    – Ceving

    7. März 2013 um 18:17 Uhr

  • @ceving NodeList ist eine Schnittstelle. Implementierungen sind frei, um fortgeschrittene Dinge zu tun. Die item(n)-Implementierung in org.apache.xerces.dom.ParentNode enthält einen Cache, aber er wird verwendet, um die Suche zu beschleunigen, nicht um Speicher zu sparen.

    – Ryan

    20. August 2014 um 18:32 Uhr

  • Fahren Sie mit Antwort #2 fort, aber ändern Sie die for-Schleife wie folgt: for (int i = 0, len = nodeList.getLength(); i < len; i++)

    – Andreas

    24. Mai 2018 um 5:39 Uhr

Benutzer-Avatar
Andreas

for (int i = 0; i < nodeList.getLength(); i++)

ändern

for (int i = 0, len = nodeList.getLength(); i < len; i++)

effizienter zu sein.

Die zweite Art der Javanna-Antwort ist möglicherweise die beste, da sie dazu neigt, ein flacheres, vorhersagbares Speichermodell zu verwenden.

  • Sie benötigen mindestens 50 Wiederholungen, um einen Kommentar abgeben zu können. Ich hatte das gleiche Problem und antwortete, weil ich nichts dazu sagen konnte. Haben Sie etwas Upvote-Hilfe;)

    – Nyaray

    11. Juli 2013 um 16:54 Uhr


  • Die obige Lösung zur Vermeidung von Rekursionen verhindert, dass das Programm basierend auf den Daten mehr Stapelspeicher verwendet. Jeder Schritt in der Rekursion schiebt mehr Daten in den Stack.

    – Andreas

    30. März 2018 um 14:57 Uhr

Benutzer-Avatar
Mike

Über dieses Problem bin ich auch vor kurzem gestolpert. Hier ist meine Lösung. Ich wollte Rekursion vermeiden, also habe ich eine While-Schleife verwendet.

Aufgrund der Hinzufügungen und Entfernungen an beliebigen Stellen in der Liste habe ich mich für die entschieden LinkedList Implementierung.

/* traverses tree starting with given node */
  private static List<Node> traverse(Node n)
  {
    return traverse(Arrays.asList(n));
  }

  /* traverses tree starting with given nodes */
  private static List<Node> traverse(List<Node> nodes)
  {
    List<Node> open = new LinkedList<Node>(nodes);
    List<Node> visited = new LinkedList<Node>();

    ListIterator<Node> it = open.listIterator();
    while (it.hasNext() || it.hasPrevious())
    {
      Node unvisited;
      if (it.hasNext())
        unvisited = it.next();
      else
        unvisited = it.previous();

      it.remove();

      List<Node> children = getChildren(unvisited);
      for (Node child : children)
        it.add(child);

      visited.add(unvisited);
    }

    return visited;
  }

  private static List<Node> getChildren(Node n)
  {
    List<Node> children = asList(n.getChildNodes());
    Iterator<Node> it = children.iterator();
    while (it.hasNext())
      if (it.next().getNodeType() != Node.ELEMENT_NODE)
        it.remove();
    return children;
  }

  private static List<Node> asList(NodeList nodes)
  {
    List<Node> list = new ArrayList<Node>(nodes.getLength());
    for (int i = 0, l = nodes.getLength(); i < l; i++)
      list.add(nodes.item(i));
    return list;
  }

1217370cookie-checkJava: Effizienteste Methode, um alle Elemente in einem org.w3c.dom.Document zu durchlaufen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy