How to skip specific element in SimpleXML
Asked Answered
F

2

9

I am using SimpleXML framework for deserializing backend answers. I made some assumptions about elements. Some elements do not meet these requirements. For example, I expect an element to have childs <ID> and <face>. If my user is not allowed to see a specific element, I might get an answer like this:

<list>
  <voucher type="hiddenobject">
    <face>foo</face>
  </voucher>
  <voucher type="object">
    <ID>42</ID>
    <face>bar</face>
  </voucher>
</list>

Which gives me a ValueRequiredException for the following deserialization class:

@Root
class Voucher {
  @Element(name="ID")
  private String id;

  @Element
  private String face;
}

I would like to ignore these objects with type hiddenobject. I learned about the VisitorStrategy and implemented a simple Visitor like so:

private static final class HiddenObjectVisitor implements Visitor {

    @Override
    public void read(Type type, NodeMap<InputNode> node) throws Exception {
        String nodeType = node.getNode().getAttribute("type").getValue();

        if (nodeType != null && nodeType.equals("hiddenobject")) {
            Log.d(TAG, "skipping node " + node);
            node.getNode().skip();
        }
    }

    @Override
    public void write(Type type, NodeMap<OutputNode> node) throws Exception {
        // stub
    }
}

and added this Visitor to a VisitorStrategy

VisitorStrategy strategy = new VisitorStrategy(new HiddenObjectVisitor());

expecting that this would skip nodes during deserialization. I do get log entries stating that the node would be skipped. Anyway, the VisitorStrategy seems to keep parsing the node to be skipped, resulting in a ValueRequiredException.

How can I ignore nodes having a given attribute? Is it possible to use VisitorStrategy for this task?

Flannery answered 25/10, 2016 at 10:10 Comment(1)
is it advisable to have class ActiveVoucher extends Voucher, where ActiveVoucher would have required attributes, while Voucher wont have required attributes ?Fisherman
C
5

You could probably combine the approach suggested by Raniz with your HiddenObjectVisitor. Annotate id with required=false to avoid the ValueRequiredException, and then use your HiddenObjectVisitor to skip some of the Voucher objects during deserialization.

Based on the XML that you have shown, id is not required in the XML file, and that is what required=false indicates. But you imply that id is required in your deserialized objects, so you can discard the invalid objects at the time of deserialization.

Caernarvonshire answered 1/11, 2016 at 19:2 Comment(0)
N
4

One thing you can do is to mark ID as optional and include the type attribute so you can filter after deserialisation.

@Root
class Voucher {
  @Attribute
  private String type;

  @Element(name="ID", required=false)
  private String id;

  @Element
  private String face;
}

You can then filter the vouchers after they have been deserialised:

// Deserialise the XML
List<Voucher> vouchers = ...;

// Filter the list of vouchers
List<Voucher> nonHiddenVouchers = new ArrayList<>();
for (Voucher voucher : vouchers) {
    if (!"hiddenobject".equals(voucher.getType())) {
        nonHiddenVouchers.add(voucher);
    }
}
Nevillenevin answered 28/10, 2016 at 8:47 Comment(1)
Thanks, but I already thought about that. I would like to keep my assumptions about valid objects. For example, I use ID in .equals(), where it would be bad to have a null ID.Flannery

© 2022 - 2024 — McMap. All rights reserved.