Получить строку / столбец запроса XPath в Pugixml
Мы хотим получить строку / столбец результата запроса xpath в pugixml:
pugi::xpath_query query_child(query_str);
std::string value = Convert::toString(query_child.evaluate_string(root_node));
Мы можем получить смещение, но не строку / столбец:
unsigned int = query_child.result().offset;
Если мы повторно проанализируем файл, мы можем преобразовать смещение => (строка, столбец), но это неэффективно.
Есть ли эффективный метод для достижения этой цели?
1 ответ
result().offset - последнее проанализированное смещение в строке запроса; оно будет равно 0, если запрос был успешно проанализирован; так что это не смещение в XML-файле.
Для запросов XPath, которые возвращают строки, понятие "смещение в XML-файле" не определено, то есть чего вы ожидаете
concat("a", "b")
запрос?Для запросов XPath, которые возвращают узлы, вы можете получить смещение данных узла в файле. К сожалению, из-за разборов производительности и потребления памяти эту информацию невозможно получить без повторного анализа. В списке TODO есть задача сделать это проще (например, с помощью нескольких строк кода), но это займет некоторое время.
Итак, если вы хотите найти смещение узла, являющееся результатом запроса XPath, единственный способ - получить результат запроса XPath в виде набора узлов (query.evaluate_node_set
или же node.select_single_node/select_nodes
), получить смещение (node.offset_debug()
) и преобразовать его в строку / столбец вручную.
Вы можете подготовить структуру данных для смещения -> преобразования строки / столбца один раз, а затем использовать ее несколько раз; например, следующий код должен работать:
#include <vector>
#include <algorithm>
#include <cassert>
#include <cstdio>
typedef std::vector<ptrdiff_t> offset_data_t;
bool build_offset_data(offset_data_t& result, const char* file)
{
FILE* f = fopen(file, "rb");
if (!f) return false;
ptrdiff_t offset = 0;
char buffer[1024];
size_t size;
while ((size = fread(buffer, 1, sizeof(buffer), f)) > 0)
{
for (size_t i = 0; i < size; ++i)
if (buffer[i] == '\n')
result.push_back(offset + i);
offset += size;
}
fclose(f);
return true;
}
std::pair<int, int> get_location(const offset_data_t& data, ptrdiff_t offset)
{
offset_data_t::const_iterator it = std::lower_bound(data.begin(), data.end(), offset);
size_t index = it - data.begin();
return std::make_pair(1 + index, index == 0 ? offset : offset - data[index - 1]);
}
Это не обрабатывает разрывы строк в стиле Mac и не обрабатывает вкладки; это, конечно, можно добавить тривиально.