Самый быстрый способ подсчитать / получить доступ к детям DOMNode с помощью Xerces C++

Я пытаюсь выяснить самый быстрый способ подсчета количества дочерних элементов объекта DOMNode Xerces C++, поскольку я пытаюсь оптимизировать производительность приложения Windows, которое использует DOMParser Xerces 2.6. Кажется, большую часть времени тратят на подсчет и доступ к детям. Наше приложение должно выполнить итерацию каждого узла в документе, чтобы присоединить к нему данные, используя DOMNode::setUserData(), и мы изначально использовали DOMNode::getChildNodes(), DOMNodeList::getLength() и DOMNodeList::item(int index) считать и получать доступ к детям, но это сравнительно дорогие операции.

Значительное улучшение производительности наблюдалось, когда мы использовали другую идиому вызова DOMNode:: getFirstChild() для получения первого дочернего узла и вызова DOMNode::getNextSibling() для доступа к дочернему элементу по определенному индексу или для подсчета числа братьев и сестер первый дочерний элемент, чтобы получить общее количество дочерних узлов.

Однако getNextSibling () остается узким местом на нашем этапе анализа, поэтому мне интересно, есть ли еще более быстрый способ обхода и доступа к дочерним элементам с помощью Xerces.

Спасибо

1 ответ

Проблема с DOMNodeList состоит в том, что это действительно довольно простой список, поэтому такие операции, как length и item(i) иметь расходы на O(n)как можно увидеть в коде, например здесь для длины:

XMLSize_t DOMNodeListImpl::getLength() const{
    XMLSize_t count = 0;
    if (fNode) {
        DOMNode *node = fNode->fFirstChild;
        while(node != 0){
            ++count;
            node = castToChildImpl(node)->nextSibling;
        }
    }

    return count;
}

Таким образом, DOMNodeList не следует использовать, если не ожидается, что DOM-дерево будет изменено во время итерации, потому что доступ к элементу в O(n) таким образом делая итерацию O(n^2) операция - ожидающая катастрофа катастрофа (т.е. достаточно большой xml-файл).

С помощью [DOMNode::getFistChild()][2] и DOMNode::getNextSibling() достаточно хорошее решение для итерации:

DOMNode *child = docNode->getFirstChild();
while (child != nullptr) {
    // do something with the node
    ...
    child = child->getNextSibling();
}

Что происходит, как ожидалось в O(n^2).

Можно также использовать [DOMNodeIterator][3], Но для того, чтобы создать его право DOMDocument требуется, что не всегда под рукой, когда требуется итерация.

Да, вскоре после публикации я добавил код для хранения и управления количеством дочерних элементов для каждого узла, и это имело большое значение. Одни и те же узлы посещались неоднократно, и каждый раз пересчитывалось количество детей. Это довольно дорогая операция, поскольку Xerces существенно перестраивает структуру DOM для этого узла, чтобы гарантировать его жизнеспособность. У нас есть собственный объект, который инкапсулирует DOMNode Xerces вместе с дополнительной информацией, которая нам нужна, и мы используем DOMNode::setUserData, чтобы связать наш объект с соответствующим DOMnode, и теперь он, похоже, является последним остающимся узким местом.

Другие вопросы по тегам