2011-01-27 2 views
3

Мы хотим получить строку/столбец в результате 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; 

Если мы повторно проанализируем файл, мы можем преобразовать offset => (строка, столбец), но это не эффективно.

Есть ли способ для этого?

ответ

2
  1. результат(). Offset - это последнее проанализированное смещение в строке запроса; он будет равен 0, если запрос успешно проанализирован; поэтому это не смещение в файле XML.

  2. Для запросов XPath, возвращающих строки, понятие «смещение в файле XML» не определено - то есть, что вы ожидаете от concat("a", "b") запроса?

  3. Для запросов 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-стиле и не обрабатывает вкладок; Конечно, это может быть тривиально добавлено.

+0

Спасибо, да, я хочу найти смещение узла. Но вопрос в том, как преобразовать в строку/столбец без повторного разбора? Возможно, мне нужно изменить код pugixml? –

+0

И ответ - вы не можете. Вы можете отредактировать код pugixml, но это будет непросто - по соображениям производительности нет lexer, поэтому нет единственного места, где вы можете рассчитывать символы новой строки. Лучше всего репарация; вы можете выполнить однократную переупаковку один раз, построив std :: map с ключом = сдвигом новой строки и значением = индекс строки (увеличение числа); то вы можете использовать equal_range для преобразования смещения в столбец row +. Не нужно изменять код pugixml. – zeuxcg

+0

Я обновил ответ с помощью примера кода. – zeuxcg

Смежные вопросы