Java-код VTD-XML получает только первые элементы

XML-документ:

<?xml version="1.0" encoding="utf-8"?>
<vdsDataSet>
  <date>1900-01-01</date>
  <vdsData>
    <contractId>contractId1</contractId>
    <periodNum>1</periodNum>
    ...
  </vdsData>
  <vdsData>
    <contractId>contractId2</contractId>
    <periodNum>-128</periodNum>
 ...
  </vdsData>
</vdsDataSet>

Я пытаюсь получить все идентификаторы контрактов и все связанные с ними номера периодов. Итак, вывод должен выглядеть так:

contractId1
1
contractId2
-128

Прямо сейчас я получаю только:

contractId1
1

Вот мой код:

    VTDGen vg = new VTDGen();
    vg.parseFile("vdsDataSet.xml",false);
    VTDNav vn = vg.getNav();
    AutoPilot ap = new AutoPilot(vn);
    int result = -1;
    ap.selectXPath("/vdsDataSet/vdsData/contractId");
    while((result = ap.evalXPath())!=-1){
        int t = vn.getText(); // get the index of the text (char data or CDATA)
        String g = null;
        if (t!=-1)
        {
            g = "" + vn.toNormalizedString(t);
            System.out.println(g);
            AutoPilot ap2 = new AutoPilot(vn);
            ap2.selectXPath("/vdsDataSet/vdsData/periodNum[../contractId=\""+g+"\"]");
            int result2= -1;
            while((result2 = ap2.evalXPath())!=-1){
                int t1 = vn.getText(); // get the index of the text (char data or CDATA)
                if (t1!=-1)
                    System.out.println(""+vn.toNormalizedString(t1));

            }

        }   
    }

Кто-нибудь знает, как я могу это исправить, чтобы он отображал ВСЕ идентификаторы контрактов и соответствующие номера периодов?

Если есть кто-нибудь, кто может мне помочь, ваша помощь будет очень признательна. Заранее спасибо!

Редактировать: Маркус попросил меня сначала добавить версию с циклом через vdsData. Вот мой код:

    ap.selectXPath("/vdsDataSet/vdsData");
    while((result = ap.evalXPath())!=-1){
AutoPilot ap2 = new AutoPilot(vn);
             ap2.selectXPath("/vdsDataSet/vdsData/contractId");
             int result2= -1;
             while((result2 = ap2.evalXPath())!=-1){
                 int t1 = vn.getText(); // get the index of the text (char data or CDATA)
                 if (t1!=-1)
                  System.out.println(""+vn.toNormalizedString(t1));
         }
             ap2.selectXPath("/vdsDataSet/vdsData/periodNum");
             int result21= -1;
             while((result21 = ap2.evalXPath())!=-1){
                 int t1 = vn.getText(); // get the index of the text (char data or CDATA)
                 if (t1!=-1)
                  System.out.println(""+vn.toNormalizedString(t1));

     }

К сожалению, это дает только следующее:

contractId1
contractId2
1
-128

скорее, чем:

 contractId1
 1
 contractId2
 -128

Добавлена ​​слегка измененная версия решения vtd-xml-author (чтобы заставить его распечатать вывод и получить правильный дочерний элемент для periodnum):

    ap.selectXPath("/vdsDataSet/vdsData");
    while((result = ap.evalXPath())!=-1){
        vn.push();
        vn.toElement(VTDNav.FC,"contractId");
        int i=-1;
        i= vn.getText(); //value for contractID here
        System.out.println(vn.toNormalizedString(i)); //added in printlns
        //vn.toElement(VTDNav.P);
        vn.toElement(VTDNav.NS, "periodNum"); //added in "periodNum" after VTDNav.NS
        i=vn.getText(); 
        i= vn.getText(); // value for periodNum here
        System.out.println(vn.toNormalizedString(i));
        vn.pop();
    }

Этот код действительно работает и делает то, что я хочу... Предполагая, что есть один элемент periodNum... но что мне делать, если у меня есть несколько PeriodNums?


person dunce1    schedule 07.12.2013    source источник
comment
Я думаю, что вы реструктурировали свой код, чтобы перебирать узлы <vsdData>, используя выражение XPath "vdsDataSet/vdsData" для своего цикла. В цикле вы выполняете два относительных запроса XPath, используя узел результата вашего итератора цикла в качестве отправной точки и "contractId" и "periodNum" в качестве выражений XPath.   -  person Marcus Rickert    schedule 07.12.2013
comment
Пробовал это. Он показывает contractId1 contractId2 1 -128 в каждой строке соответственно. Я хочу, чтобы он показывал ContractId1 1 ContractId2 -128, чтобы я мог хранить их в базе данных в ближайшем будущем и иметь возможность связать элементы с ContractId. Спасибо за помощь.   -  person dunce1    schedule 07.12.2013
comment
Как он может показывать contractId1 contractId2 1 -128, когда вы используете относительные пути в цикле по <vsdData>. Можете ли вы добавить эту версию к своему вопросу, потому что я думаю, что это лучшая отправная точка для решения.   -  person Marcus Rickert    schedule 08.12.2013
comment
Сделанный. Я думаю, причина в том, как работает XPath. Он выбирает все узлы данных, относящиеся к этому элементу. При выборе vdsData выбираются все узлы vdsData и так далее. Чтобы он был конкретным, он должен быть упомянут в XPath, я думаю, так же, как я сделал это в своем коде (хотя в моем коде по какой-то причине он выбирает только первый ContractId).   -  person dunce1    schedule 10.12.2013
comment
эта проблема считается решенной?   -  person vtd-xml-author    schedule 10.12.2013
comment
Нет, еще нет.... Вы можете помочь?   -  person dunce1    schedule 10.12.2013
comment
Я думаю, вы можете использовать xpath для получения vdsData, затем в цикле while вручную вызвать toElement (FirstChild или последний дочерний элемент), а затем использовать getText для получения текстового значения для contractID или periodNum... нужен пример или вы хотите попробовать ?   -  person vtd-xml-author    schedule 10.12.2013
comment
Да, можно пример? Спасибо!   -  person dunce1    schedule 10.12.2013
comment
Обращение к Element ns..   -  person vtd-xml-author    schedule 14.12.2013
comment
Вы имеете в виду повторение vn.toElement(VTDNav.NS, periodNum);? Если да, то можно ли как-то разобрать все элементы periodNum для каждого contractId?   -  person dunce1    schedule 14.12.2013
comment
Разобрать? Я думаю, вы имели в виду восстановить?   -  person vtd-xml-author    schedule 15.12.2013
comment
Извините ... Просто перечитал свой вопрос и понял, что это не имеет смысла. Я имел в виду получение текста во всех элементах periodNum для каждого contractId. Итак, если у меня есть более одного элемента periodNum, есть ли способ просто получить их все вместо повторного вызова VTDNav.NS (если это то, что вы имели в виду в своем исходном ответе). Спасибо.   -  person dunce1    schedule 15.12.2013
comment
Да, я так думаю... но попробуйте, в любом случае, работает ли это   -  person vtd-xml-author    schedule 16.12.2013
comment
я имел в виду, что вызов toElement(NS) необходим, иначе это не имело бы смысла...   -  person vtd-xml-author    schedule 16.12.2013
comment
Поэтому я повторил VTDNav.NS. Дело в том, что если у меня есть более одного элемента periodNum для одного элемента и только один для других элементов, он получит правильные значения для элементов periodNum для VDSData, которые имеют более одного periodNum, но затем повторят значения для каждого элемента на остальные (для VDSData, у которых есть только один элемент periodNum). Это означает, что для повторения метода toElement(NS) мне нужно иметь одинаковое число periodNum для каждого элемента vdsData.   -  person dunce1    schedule 16.12.2013
comment
это логика приложения, которую вы знаете лучше меня :)   -  person vtd-xml-author    schedule 16.12.2013


Ответы (1)


Ниже приведен один из способов сделать это. Есть и другие способы, о которых вы, возможно, сможете узнать позже. Дайте мне знать, если это работает для вас или нет.

ap.selectXPath("/vdsDataSet/vdsData");
while((result = ap.evalXPath())!=-1){
    vn.push();
    vn.toElement(VTDNav.FC,"contractID");
    int i=-1;
    i= vn.getText(); //value for contractID here
    //vn.toElement(VTDNav.P);
    vn.toElement(VTDNav.NS);
    i=vn.getText(); 
    i= vn.getText(); // value for periodNum here
    vn.pop();
}
person vtd-xml-author    schedule 11.12.2013
comment
Я отредактировал свой вопрос, включив в него слегка измененную версию вашего решения. Проблема, с которой я сталкиваюсь, заключается в попытке получить более одного периодаNum (получается только первый). Кроме того, есть ли способ получить больше информации о FC, NS и т. д. и их значении? Я пробовал смотреть API, но ничего не нашел... Спасибо за помощь! - person dunce1; 12.12.2013
comment
Fc — это сокращение от первого потомка, а ns — следующий брат. - person vtd-xml-author; 14.12.2013
comment
Поскольку toElement() возвращает логическое значение for(boolean el = vn.toElement(VTDNav.NEXT_SIBLING, periodNum)); эль == правда ; el = vn.toElement(VTDNav.NEXT_SIBLING, periodNum)) { i=vn.getText(); System.out.println(vn.toNormalizedString(i)); } - person Dazed; 24.01.2014