Выбор узла с использованием XPath в libxml2

У меня есть XML-документ, подобный следующему.

<library>
  <artist name="a">
   <album name="1"></album>
   <album name="2"></album>
  </artist>
  <artist name="b">
   <album name="8"></album>
   <album name="9"></album>
  </artist>
</library>`

Я пишу приложение на Vala в Ubuntu и использую библиотеку libxml2 для управления XML-документом. Я хотел получить все узлы album независимо от их положения в документе. Я написал следующий фрагмент кода для выполнения вышеупомянутой работы.

document = Xml.Parser.parse_file (PATH_TO_DB);
...
Xml.XPath.Context context;
unowned Xml.XPath.Object *object;

context = new Xml.XPath.Context(document);
object = context.eval("//album");

if(object->nodesetval->is_empty())
    return null;

return object->nodesetval->item(0);
...

Этот запрос XPath возвращает только альбомы под номером artist a, т. е. альбомы 1 и 2. Однако context.eval("/library/artist[@name="b"]/album"); возвращает все альбомы под номером artist b.

Эквивалент показанного выше кода на Python дает желаемый результат.

doc = libxml2.parseFile("data.xml")
ctxt = doc.xpathNewContext()
res = ctxt.xpathEval("//album")

Что не так с кодом Валы?


person Utsav    schedule 20.10.2013    source источник


Ответы (1)


Во-первых, вы должны проверить, что возвращаемый объект является набором узлов, проверив object->type == Xml.ObjectType.NODESET.

Затем вы возвращаете только первый элемент в результирующем наборе узлов. Есть nodeset->length() предметов.

void main() {
    var document = Xml.Parser.parse_file ("file.xml");
    run_query("//album", document);
    run_query("/library/artist[@name=\"b\"]/album", document);
}

void run_query(string query, Xml.Doc* document) {
    stdout.printf("Query: %s\n", query);
    Xml.XPath.Context context;
    unowned Xml.XPath.Object *object;

    context = new Xml.XPath.Context(document);
    object = context.eval(query);
    assert(object->type == Xml.XPath.ObjectType.NODESET);

    if(object->nodesetval->is_empty()) {
        stdout.printf("empty");
        return;
    }

    for (var i = 0; i < object->nodesetval->length(); i++) {
        var node = object->nodesetval->item(i);
        stdout.printf("node %s name=\"%s\"\n", node->name, node->get_prop("name"));
    }
}

Производит:

Query: //album
node album name="1"
node album name="2"
node album name="8"
node album name="9"
Query: /library/artist[@name="b"]/album
node album name="8"
node album name="9"
person apmasell    schedule 20.10.2013