简体   繁体   中英

Java: Concatinate two XML NodeList

I want to concatenate two node lists and get a new node list. At the moment my XML documents look like this: First XML:

<machine>
<values>
<value1> <...> </value1>
<value2> <...> </value2>
</values>

<days>
<value1> <...> </value1>
<value2> <...> </value2>
</days>
</machine>

Second XML:

<machine>
<values>
<value3> <...> </value1>
<value4> <...> </value2>
</values>

<days>
<value3> <...> </value1>
<value4> <...> </value2>
</days>
</machine>

at the moment I am only using one XML with the following:

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = null;
document = builder.parse(myxml.xml);
NodeList values = document.getElementsByTagName("values");
NodeList days = document.getElementsByTagName("days");

and then working on the NodeList with values & days. My program is working fine. Now I create a second list, the same way, so:

DocumentBuilderFactory factory2 = DocumentBuilderFactory.newInstance();
DocumentBuilder builder2 = factory2.newDocumentBuilder();
Document document2 = null;
document2 = builder2.parse(myxml_second.xml);
NodeList values2 = document.getElementsByTagName("values");
NodeList days2 = document.getElementsByTagName("days");

This raises the question: How can I concatenate the two lists, so that I have one list values and one list days ?

I need a new NodeList (type), cause my whole program works with the NodeList type.

I found several threads to that problem, but nothing works or returns another type but not a NodeList. One method worked:

public static NodeList join(final NodeList... lists) {

    class JoinedNodeList implements NodeList {
      public int getLength() {
        int len = 0;
        for (NodeList list : lists) {
          len += list.getLength();
        }
        return len;
      }

      public Node item(int index) {
        for (NodeList list : lists) {
          if (list.getLength() > index) {
            return list.item(index);
          } else {
            index -= list.getLength();
          }
        }
        return null;
      }
    }

    return new JoinedNodeList();
  }

Then my program works with the concatenated NodeList perfectly but it gets sick slow! I think it comes from the overwriting the two methods, cause I use them a lot in while or for loops. Without the concatenation and only one big list the program is very fast.

I'd like to suggest the following optimisations which may address your "sick slow" issue.

  • Compute the length once during construction, as this will not change.
  • Flatten the NodeList instances into a primitive array during construction so item() does not have to do as much work.

Assumptions

  • Lists are not required to be dynamic, ie DOM changes not reflected in lists, this is likely as I don't think results returned by getElementsByTagName() are dynamic anyway
  • Documents are relative small so that extra memory isn't an issue.
  • There are lots of reads later on meaning extra work during construction has a return on investment.

Code

public static NodeList join(final NodeList... lists) {

    int count = 0;
    for (NodeList list : lists) {
        count += list.getLength();
    }
    final int length = count;

    Node[] joined = new Node[length];
    int outputIndex = 0;
    for (NodeList list : lists) {
        for (int i = 0, n = list.getLength(); i < n; i++) {
            joined[outputIndex++] = list.item(i);
        }
    }
    class JoinedNodeList implements NodeList {
        public int getLength() {
            return length;
        }

        public Node item(int index) {
            return joined[index];
        }
    }

    return new JoinedNodeList();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM