3

I have a simple class (for testing purposes) that I am trying to Query against using JXPath.

I create a list of various animal objects, and I want to get an Iterator for:

  1. All Animals where type='CAT'

  2. All Animals where numLegs = 4

Here is the simple class:

public class Animal {

    private UUID uuid;
    private int numLegs;
    private AnimalType type;

    public enum AnimalType {
        CHICKEN, FROG, DOG, CAT
    }

    public Animal(AnimalType type) {
        this.type = type;
        uuid = UUID.randomUUID();
        switch (type) {
        case CHICKEN:
            numLegs = 2;
            break;
        case FROG:
            numLegs = 2;
            break;
        case DOG:
            numLegs = 4;
            break;
        case CAT:
            numLegs = 4;
            break;
        }
    }

    public UUID getUuid() {
        return uuid;
    }

    public int getNumLegs() {
        return numLegs;
    }

    public AnimalType getType() {
        return type;
    }

    public String toString(){
        return "UUID: "+uuid+", Animal: "+type+ ", Legs: "+numLegs;
    }

}

Here is the method I am using to build a list of Animals for me to Query against:

private static List<Animal> getAnimals(int numAnimals) {
    ArrayList<Animal> animals = new ArrayList<Animal>();
    for(int i = 0; i<numAnimals; i++){
        if(i%4==0){
            animals.add(new Animal(AnimalType.CAT));
        }
        else if(i%3==0){
            animals.add(new Animal(AnimalType.DOG));
        }
        else if(i%2==0){
            animals.add(new Animal(AnimalType.FROG));
        }
        else{
            animals.add(new Animal(AnimalType.CHICKEN));
        }

    }

    return animals;
}

Here is how I am trying to perform the query:

public static void main(String[] args){
    List<Animal> animals = getAnimals(10000);

    JXPathContext animsContext = JXPathContext.newContext(animals);

    Iterator<BeanPointer> iter = 
        animsContext.iteratePointers("/*[type='CAT']");

    List<Animal> cats = new ArrayList<Animal>();


    while(iter.hasNext()){
        cats.add((Animal) iter.next().getParent().getValue());
    }
    System.out.println("Number of Cats is: "+cats.size());
}

This part:

    Iterator<BeanPointer> iter = 
        animsContext.iteratePointers("/*[type='CAT']");

is not working. What am I doing wrong? I cannot get it to work for /*[numLegs=4] either.

2 Answers 2

5

I've never used JXPath, but i would expect there to be a root node, in which case

/*[type='CAT']   

would mean "give me the root node, only if it has an attribute of type equal to CAT"

I think what you are after is something more like

/*/*[type='CAT']

which would read like "give me nodes directly underneath the root node that have an attribute type which is equal to CAT"

Brian's suggestion

//*[type='CAT'] 

reads like "give me all nodes anywhere in the tree that have an attribute type that is equal to CAT"

Hope that helps a bit.

Sign up to request clarification or add additional context in comments.

Comments

2

I'm not sure what's not working in the above. However a couple of points.

  1. I'm not sure enumerations work as you expect. Your JXPath query is querying for a type where getType() will return an enumeration and not a string. I'm not sure if JXPath is that clever wrt. enumerations.
  2. [type='CAT'] by itself isn't an XPath expression. I would expect something like //*[type='CAT']

So I would try the following:

  1. implement a getTypeName() method that returns the enumeration name e.g. CAT/DOG etc. and query using that
  2. Try an XPath of //* (without any predicates) to confirm that JXpath will query an ArrayList as expected.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.