2014-10-23 3 views
1

Я хочу объединить два списка узлов и получить новый список узлов. На данный момент мои XMLs выглядеть следующим образом: Первый XML:Java: Совместить два XML NodeList

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

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

Второй XML:

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

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

в данный момент я только с помощью одного XML со следующим:

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"); 

а затем работает с значениями NodeList & дней. Моя программа работает нормально. Теперь я создать второй список, точно так же, так:

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"); 

И теперь возникает вопрос: Как я могу объединить два списка, так что у меня есть один список «ценности» и один список «дней «?

Мне нужен новый NodeList (тип), потому что вся моя программа работает с типом NodeList.

Я нашел несколько потоков для этой проблемы, но ничего не работает или возвращает другой тип, но не NodeList. Один из методов работы:

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(); 
    } 

Чем моя программа работает с конкатенированным NodeList отлично, но она заболевает медленно! Я думаю, что это происходит из-за перезаписи двух методов, потому что я использую их много в while или для циклов. Без конкатенации и только одного большого списка программа очень быстрая.

+1

вам нужно 'NodeList's ли продолжать быть динамичным? –

+0

Попробуйте col.retainAll (otherCol) // для пересечения и col.addAll (otherCol) // для объединения из класса Collection и посмотреть, есть ли улучшения –

+0

@ T.J. Crowder Dynamic? Я не знаю что ты имеешь ввиду. Этот кодовый блок выше вызывается после запуска программы, а затем я просто работаю с значениями/днями NodeLists. – asdf

ответ

1

Я хотел бы предложить следующие оптимизации, которые могут адресовать ваш «больной медленный» вопрос.

  • Вычислить длину один раз во время строительства, так как это не изменится.
  • Сгладить экземпляры NodeList в примитивный массив во время построения, поэтому item() не должен выполнять столько работы.

Предположения

  • Списки не должны быть динамичными, т.е. DOM изменения не отражены в списках, это, вероятно, так как я не думаю, что результаты, возвращаемые getElementsByTagName() являются динамичными в любом случае
  • Документы относительно малы, поэтому дополнительная память не является проблемой.
  • Существует много сообщений позже о том, что дополнительная работа во время строительства имеет возврат инвестиций.

Код

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(); 
} 
+0

Идеальный, идеальный, идеальный. Спасибо огромное! его даже быстрее, чем моя старая версия с одним списком :) И решение настолько простое. PS: мое затмение принимает только узел [], присоединенный как final. Зачем? но он работает :) – asdf

+0

@asdf: Это было причиной моего вопроса, прежде чем я пошел на обед. :-) (экземпляры 'NodeList' являются динамическими, что означает, что если базовый документ изменяется таким образом, который влияет на' NodeList', вы видите это изменение, отраженное в 'NodeList'. Реализация в вашем вопросе подтверждает это, но при значительная стоимость. Реализация Адама не поддерживает его, что приводит к значительному повышению производительности.) –

+0

@TJCrowder в порядке спасибо за объяснение! Где добросердечный форум задавал вопросы, хотя во время моего обучения Google приносил мне много раз вам :) Спасибо! – asdf