• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Tim Cooke
  • Campbell Ritchie
  • Ron McLeod
  • Junilu Lacar
  • Liutauras Vilda
Sheriffs:
  • Paul Clapham
  • Jeanne Boyarsky
  • Henry Wong
Saloon Keepers:
  • Tim Moores
  • Tim Holloway
  • Stephan van Hulst
  • Piet Souris
  • Carey Brown
Bartenders:
  • Jesse Duncan
  • Frits Walraven
  • Mikalai Zaikin

JDOM Element.getDescendants(Filter filter) driving me crazy

 
Greenhorn
Posts: 4
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi everyone, this is my first post so behave please .

To introduce myself i study computer science in Denmark at the university of Aarhus, 1st year, 2nd semester. So i'm failry new to Java but i get the general idea.

I've written a method to get data from xml input which takes 4 parameters: an org.jdom.Document, String to specify element through org.jdom.filter.ElementFilter, String to specify attribute and a String to specify the attributeValue.

XHTML source: Pastebin (yes i'm trying to datamine the WoW Armory through xhtml, since they won't supply XML feeds anymore)

<div id="wrapper">
<div id="header">
<div id="search-bar">
<form action="/wow/en/search" method="get" id="search-form">
<div>
<input type="submit" id="search-button" value="" tabindex="41"/>
<input type="text" name="q" id="search-field" maxlength="200" tabindex="40" alt="Search the Armory, forums and more…" value="Search the Armory, forums and more…" />
</div>
</form>
</div>
<h1 id="logo"><a href="/wow/en/">World of Warcraft</a></h1>
<div class="header-plate">
<ul id="menu">
<li class="menu-home">
<a href="/wow/en/"><span>Home</span></a>
</li>
<li class="menu-game">
<a href="/wow/en/game/" class="active"><span>Game</span></a>
</li>
<li class="menu-community">
<a href="/wow/en/community/"><span>Community</span></a>
</li>
<li class="menu-media">
<a href="/wow/en/media/"><span>Media</span></a>
</li>
<li class="menu-forums">
<a href="/wow/en/forum/"><span>Forums</span></a>
</li>
<li class="menu-services">
<a href="/wow/en/services/"><span>Services</span></a>
</li>
</ul>
<div class="user-plate ajax-update">
<div class="user-meta meta-login">
<a href="?login" onclick="return Login.open('https://eu.battle.net/login/login.frag')"><strong>Log in</strong></a> with your Battle.net account to post comments and personalize your site content.
</div>
</div>
</div>
</div>
</div>

The method call: (in a try/catch block printing exceptions if the occur)

String serverName = "Lilwaynez"; (this is stored locally on an XML file)
String charName = "Nordrassil";

//Open connection to the wow-armory
url = new URL("http://eu.battle.net/wow/en/character/"+ serverName +"/"+ charName +"/simple");
con = (HttpURLConnection)url.openConnection();

//Connection properties
con.setRequestMethod("GET");
con.setDoInput(true);
con.setDoOutput(true);
con.setUseCaches(false);
con.setDefaultUseCaches(false);

//Get InputStream from connection
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));

//Build the document holding char data
charData = (Document)b.build(in);

//Get root element and check if the document even has one
Element charRoot = charData.getRootElement();
Boolean rootElementTrue = charData.hasRootElement();
System.err.println("root element is: " + rootElementTrue + " - "+ charRoot.toString());

//method call
System.out.println("\n");
System.out.println("******CHECKING GETCHARDATA METHOD*******");
System.out.println(getCharData(charData, "div", "id", "header-plate").toString());

The method:

public Element getCharData(Document doc, String element, String attribute, String attributeValue){

>ElementFilter eFilter = new ElementFilter(element);
>Iterator<Element> elements = doc.getRootElement().getDescendants(eFilter); //Gets the requested elements.
>System.err.println("Found elements through getCharData()");

>Element e = null;
>while (elements.hasNext()){
>>Element ele = elements.next();
>>System.out.println("element: " + element + " found");
>>if(ele.getAttributes()!=null && ele.getAttributeValue(attribute).contains(attributeValue)){
>>>System.err.println("Element: " + ele.toString() + "found\n");
>>>System.out.println(ele.getText());
>>>e = ele;
>>>break;
>>}
>}
>return e;
}

The entire class can be seen at this link: Pastebin

The output i get from the method call on the linked org.jdom.Document:

******CHECKING GETCHARDATA METHOD*******
Found elements through getCharData()
element: div found
element: div found
element: div found
element: div found
java.lang.NullPointerException

my own theory is that it goes through the elements on one axis only, as soon as it has to go to siblings of their ancestors, it throws a NullPointerException, because no more elements of the specified kind we're found in the axis. I have no idea whether this theory is right or wrong, but it doesn't make any sense to me, as i was under the impression that descendants were every single element under the parent element.

Looking forward to a response, and i apologize for the great wall of text. Happy coding everyone .
 
Sheriff
Posts: 27235
87
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Well, wall of text aside, when I see a NullPointerException my first instinct is to decide that is a symptom of a problem in my code. So I go and look at the stacktrace which it is at the top of. That's what I would recommend you do, too. Then you can see which line of your code is incorrectly trying to dereference a null value, and fix it accordingly.
 
Soren Frank
Greenhorn
Posts: 4
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Paul Clapham wrote:Well, wall of text aside, when I see a NullPointerException my first instinct is to decide that is a symptom of a problem in my code. So I go and look at the stacktrace which it is at the top of. That's what I would recommend you do, too. Then you can see which line of your code is incorrectly trying to dereference a null value, and fix it accordingly.



>Element e = null;
>while (elements.hasNext()){
>>Element ele = elements.next();
>>System.out.println("element: " + element + " found");
>>if(ele.getAttributes()!=null && ele.getAttributeValue(attribute).contains(attributeValue)){
>>>System.err.println("Element: " + ele.toString() + "found\n");
>>>System.out.println(ele.getText());
>>>e = ele;
>>>break;
>>}
>}
>return e;
}

Reference to null value is written in red, this is what i expected and tried to counter with ele.getAttributes()!=null, doesn't seem to work though :(

and thanks for the swift response!
 
Ranch Hand
Posts: 734
7
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
This is how you set up the conditioning.

getAttributes() returns a type java.util.List that could be empty that is what to guard against. And then getAttributeValue() of a nonexisting attribute returns null and null cannot do .contains() that would be the NullPointerException.
 
Soren Frank
Greenhorn
Posts: 4
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I tried setting up the condition as you said, still returned a nullPointerException. something interesting though is, that i tried testing it on the root element <html>, when i did that, it seemed to go into an eternal while loop printing element: html found until i manually stopped it.

Might have something to do with it but i can't seem to figure out why it enters this state.

This is the method as it is now:

 
Paul Clapham
Sheriff
Posts: 27235
87
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
It's because you keep getting a new iterator for "elements", so you keep starting at the beginning every time around the loop.
 
g tsuji
Ranch Hand
Posts: 734
7
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
[0] I wonder why you silently change the use of getDescendants() to getContent(), without apparently fully appreciate the meaning of the latter. If you pass Document to the method, I would suggest you stick to the getDescendants() in the first post. After the proper set up of the conditional, the method should return either null (not actually found the desired element) and you've to control this possible outcome (of null) otherwise, naturally, you could get again, for different reason, NullPointerException for operating on it which you should not. Or, you would get the first encounter of the desired element. That should be the intention of the method.

[1] If you use getContent(), you should note that it means only the first level of child nodes of the Document doc which of course is of very limited use. Going deeper levels (descendants again) would need some recursion with the first argument being element in general (not Document). That is not too difficult but certainly not fun.

[1.1] The iteration in the getContent() case is incorrect. It should look something like this, if you want to know why it takes that "long", actually infinite loop.
 
Soren Frank
Greenhorn
Posts: 4
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Paul Clapham wrote:It's because you keep getting a new iterator for "elements", so you keep starting at the beginning every time around the loop.



I'm quite embarrassed I missed that myself :(

As for getContent() I was messing around with a few different methods which I thought could be useful, completely forgot that I switched them around. Thanks for pointing it out!

with your clarification it all makes sense now, I've only been programming for a few months, so I'm learning by failing at the moment. the method works now though, and I get the output i expected in the first place.

Once again thanks for your help, I really appreciate it!
 
Paul Clapham
Sheriff
Posts: 27235
87
Eclipse IDE Firefox Browser MySQL Database
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Soren Frank wrote:I've only been programming for a few months, so I'm learning by failing at the moment.



Here's some news for you: this is also how programmers with 40 years of experience learn. (That's if they are still learning at that age... which they should be if they want to consider themselves as programmers.)
 
pie. tiny ad:
Building a Better World in your Backyard by Paul Wheaton and Shawn Klassen-Koop
https://coderanch.com/wiki/718759/books/Building-World-Backyard-Paul-Wheaton
reply
    Bookmark Topic Watch Topic
  • New Topic