3

pugixml で xpath クエリの結果の行/列を取得します。

pugi::xpath_query query_child(query_str);
std::string value = Convert::toString(query_child.evaluate_string(root_node));

オフセットは取得できますが、行/列は取得できません:

unsigned int = query_child.result().offset;

ファイルを再解析すると、オフセット => (行、列) に変換できますが、効率的ではありません。

これを達成するための効率的な方法はありますか?

4

1 に答える 1

2
  1. result().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 スタイルの改行を処理せず、タブを処理しません。もちろん、これは簡単に追加できます。

于 2011-01-27T15:37:44.073 に答える