1

XML document:

<?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>

I am trying to get all the Contract IDs and all the associated period numbers. So output should look like this:

contractId1
1
contractId2
-128

Right now, I am only getting:

contractId1
1

Here is my code:

    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));

            }

        }   
    }

Does anyone know how I can fix this so that it shows ALL Contract ID and the associated period numbers?

If there's anyone who could help me out, your help would be greatly appreciated. Thanks in advance!

Edit: Marcus has asked me to add the version with looping through vdsData first. Here is my code:

    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));

     }

Unfortunately this only gives the following:

contractId1
contractId2
1
-128

rather than:

 contractId1
 1
 contractId2
 -128

Added a slightly modified version of vtd-xml-author's solution (to get it to print the output and to retrieve the correct child element for 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();
    }

This code actually works and does what I want it to...Assuming there is one element of periodNum...but what do I do if I have multiple periodNums?

vtd-xml-author
  • 3,319
  • 4
  • 22
  • 30
dunce1
  • 323
  • 5
  • 21
  • I think you yould restructure your code to iterate over the `` nodes using XPath expression `"vdsDataSet/vdsData"` for your loop. In the loop you do two relative XPath queries using the result node of your loop iterator as a starting point and `"contractId"` and `"periodNum"` as XPath expressions. – Marcus Rickert Dec 07 '13 at 06:32
  • Tried that. It shows "contractId1 contractId2 1 -128" on each line respectively. I want it to show "contractId1 1 contractId2 -128" so I can be able to store them in a database in the near future and be able to link the elements to the contractId. Thanks for the help though. – dunce1 Dec 07 '13 at 19:43
  • How can it show `contractId1 contractId2 1 -128` when you use relative paths in a loop over ``. Can you add this version to your question because I think it's a better starting point for the solution. – Marcus Rickert Dec 07 '13 at 21:26
  • Done. I think the reason is because the way XPath works. It selects all the data nodes pertaining to that element. When you select vdsData, it selects all vdsData nodes and so on. In order for it to be specific, it has to be mentioned in the XPath I think like the way I did it in my code (though in my code it only selects the first contractId for some reason). – dunce1 Dec 09 '13 at 21:24
  • is this problem considered solved? – vtd-xml-author Dec 10 '13 at 00:04
  • No, not yet....Can you help? – dunce1 Dec 10 '13 at 03:13
  • I think u can use xpath to get vdsData, then in the while loop manually call toElement(FirstChild or last child), and then use getText to retrieve the text value for contractID or periodNum... need example or want to give it a try? – vtd-xml-author Dec 10 '13 at 08:38
  • Yes, can you give an example? Thanks! – dunce1 Dec 10 '13 at 16:46
  • Calling more toElement ns.. – vtd-xml-author Dec 14 '13 at 01:46
  • You mean repeat vn.toElement(VTDNav.NS, "periodNum");? If so, is there anyway to parse all the elements of periodNum for each contractId? – dunce1 Dec 14 '13 at 16:25
  • Parse? I think you meant retrieve? – vtd-xml-author Dec 15 '13 at 04:54
  • Sorry...Just reread my own question and realized it doesn't make sense. I meant retrieve the text in all periodNum elements for each contractId. So if I have more than one periodNum element, is there a way to just get all of them instead of calling VTDNav.NS again (if that's what you meant in your original answer). Thanks. – dunce1 Dec 15 '13 at 05:12
  • Yes, i think so... but give it a try to see if it works in any case – vtd-xml-author Dec 15 '13 at 23:29
  • what i meant is that calling toElement(NS) is needed, otherwise it would not make sense... – vtd-xml-author Dec 15 '13 at 23:55
  • So I repeated the VTDNav.NS. The thing is, if I have more than one periodNum element on one element and only one on other elements, it will get the proper values for the periodNum elements for VDSData that has more than one periodNum, but then repeat the values for each elements on the rest (for VDSData that has only one periodNum element). Meaning, in order to repeat the toElement(NS) method, I have to have the same number of periodNum for each vdsData element. – dunce1 Dec 16 '13 at 00:13
  • that is the application logic that you know better than me :) – vtd-xml-author Dec 16 '13 at 00:14

1 Answers1

1

Below is one way of doing it. There are other ways that you might be able to figure out later. Let me know if it works for you or not.

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();
}
vtd-xml-author
  • 3,319
  • 4
  • 22
  • 30
  • I edited my question to include a slightly modified version of your solution. The problem I have is trying to get more than one periodNum (it only gets the first one). Also, is there a way I can get more information on FC, NS, etc and their meaning? I tried looking at API but couldn't find anything... Thanks for all the help! – dunce1 Dec 12 '13 at 10:20
  • 1
    Fc is short for first child and ns is next sibling. – vtd-xml-author Dec 14 '13 at 01:44
  • 1
    As "toElement()" returns a boolean for(boolean el = vn.toElement(VTDNav.NEXT_SIBLING, "periodNum")); el == true ; el = vn.toElement(VTDNav.NEXT_SIBLING, "periodNum")) { i=vn.getText(); System.out.println(vn.toNormalizedString(i)); } – Dazed Jan 24 '14 at 10:41