I am modifying a legacy code and I need to remove all elements if its id attribute is included in a string.
Example ids to remove:
String idToExclude = "2,4,6,8,10";
Assuming Element doc
contains the following:
<StoreOffers>
<Store StoreID="0">
<Offers>
<Offer OfferID="1"/>
<Offer OfferID="2"/>
<Offer OfferID="3"/>
<Offer OfferID="4"/>
<Offer OfferID="5"/>
<Offer OfferID="6"/>
<Offer OfferID="7"/>
<Offer OfferID="8"/>
<Offer OfferID="9"/>
<Offer OfferID="10"/>
</Offers>
</Store>
</StoreOffers>
EDIT This is what I've tried, this is the actual code. I've updated the xml as well:
String offersToExclude = getOffersToExclude(customer);
StringReader asa = new StringReader(storeOffers);
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(asa);
Element root = doc.getRootElement();
List<Element> stores = root.getChildren();
for (Element store : stores) {
storeid = store.getAttributeValue("StoreID");
List<Element> offers = store.getChild("Offers").getChildren();
for(Element offer : offers) {
String offerid = offer.getAttributeValue("OfferID");
if(CCSUtils.isNotEmpty(offerid)) {
if(offersToExclude.contains(offerid)) {
store.getChild("Offers").removeChild(offer); //This doesn't work
}
}
}
}
Since the version of jdom
is not known, the following solution is base on version 2.0.6 (latest as at 29/10/2018).
First, the method removeChild
is not applicable for String
argument, there is only two method: public boolean removeChild(final String cname)
and public boolean removeChild(final String cname, final Namespace ns)
.
To achieve what you expected, simply manipulate the elements get from Element.getChildren()
method of the parent Element
. As explained in Java Doc of Element.getChildren()
This returns a List of all the child elements nested directly (one level deep) within this element, as Element objects. If this target element has no nested elements, an empty List is returned. The returned list is "live"in document order and changes to it affect the element's actual contents.
Sequential traversal through the List is best done with a Iterator since the underlying implement of List.size() may not be the most efficient.
So we can use the iterator to iterate the child elements, and remove the element if the OfferID is one of our target. The following code demonstrate how this can be done.
import java.io.IOException;
import java.io.StringReader;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;
public class DeleteChild {
public static void main(String[] args) throws IOException, JDOMException {
// Should not use String.contains method as OfferId="1" will be deleted.
String[] offersToExclude = "2,4,6,8,10".split(",");
StringReader stringReader = new StringReader(getXml());
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(stringReader);
Element root = doc.getRootElement();
System.out.println("*****Before Remove*****");
System.out.println(new XMLOutputter(Format.getPrettyFormat(), null).outputString(root));
List<Element> stores = root.getChildren();
for (Element store : stores) {
List<Element> offers = store.getChild("Offers").getChildren();
Iterator<Element> offerIterator = offers.iterator();
while (offerIterator.hasNext()) {
Element offer = offerIterator.next();
if (Arrays.asList(offersToExclude).contains(offer.getAttributeValue("OfferID"))) {
offerIterator.remove();
}
}
}
System.out.println("*****After Remove*****");
System.out.println(new XMLOutputter(Format.getPrettyFormat(), null).outputString(root));
}
private static String getXml() {
return " <StoreOffers> "
+ " <Store StoreID=\"0\"> "
+ " <Offers> "
+ " <Offer OfferID=\"1\"/> "
+ " <Offer OfferID=\"2\"/> "
+ " <Offer OfferID=\"3\"/> "
+ " <Offer OfferID=\"4\"/> "
+ " <Offer OfferID=\"5\"/> "
+ " <Offer OfferID=\"6\"/> "
+ " <Offer OfferID=\"7\"/> "
+ " <Offer OfferID=\"8\"/> "
+ " <Offer OfferID=\"9\"/> "
+ " <Offer OfferID=\"10\"/> "
+ " </Offers> "
+ " </Store> "
+ "</StoreOffers> ";
}
}