From 5163af60ff8ce703bc8ab432df17812da3ae797e Mon Sep 17 00:00:00 2001 From: Carl Schroedl Date: Thu, 22 Sep 2016 15:20:09 -0500 Subject: [PATCH] Adding recursive child xml node deletion to support GS*Encoder-centric implementation of #199. --- .../rest/GeoServerRESTPublisher.java | 8 +- .../rest/encoder/utils/XmlElement.java | 33 +++++ .../rest/encoder/utils/XmlElementTest.java | 119 ++++++++++++++++++ 3 files changed, 153 insertions(+), 7 deletions(-) create mode 100644 src/test/java/it/geosolutions/geoserver/rest/encoder/utils/XmlElementTest.java diff --git a/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTPublisher.java b/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTPublisher.java index 20231fd..b025702 100644 --- a/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTPublisher.java +++ b/src/main/java/it/geosolutions/geoserver/rest/GeoServerRESTPublisher.java @@ -3273,14 +3273,8 @@ public class GeoServerRESTPublisher { String sUrl = baseUrl + "?recalculate=" + calculationMode.getParamValue(); LOGGER.debug("Constructed the following url for bounding box recalculation: " + sUrl); - -// String body = wsenc.toString(); -// String body = "<" + xmlElementName +">" + layerName + "" + -// "" + enabled + ""; - renc.remove(GSResourceEncoder.KEYWORDS); - renc.remove(GSResourceEncoder.METADATA); - renc.remove(GSResourceEncoder.METADATALINKS); + renc.recursivelyRemoveEmptyChildren(); String body = renc.toString(); String sendResult = HTTPUtils.putXml(sUrl, body, gsuser, gspass); boolean success = sendResult != null; diff --git a/src/main/java/it/geosolutions/geoserver/rest/encoder/utils/XmlElement.java b/src/main/java/it/geosolutions/geoserver/rest/encoder/utils/XmlElement.java index 63c6d91..aa7649d 100644 --- a/src/main/java/it/geosolutions/geoserver/rest/encoder/utils/XmlElement.java +++ b/src/main/java/it/geosolutions/geoserver/rest/encoder/utils/XmlElement.java @@ -26,9 +26,13 @@ package it.geosolutions.geoserver.rest.encoder.utils; +import java.util.ArrayList; +import java.util.List; import org.jdom.Content; import org.jdom.Element; import org.jdom.Text; +import org.jdom.filter.ContentFilter; +import org.jdom.filter.ElementFilter; import org.jdom.output.Format; import org.jdom.output.XMLOutputter; @@ -122,6 +126,35 @@ public class XmlElement{ return false; } + public void recursivelyRemoveEmptyChildren(){ + //must make a copy to avoid ConcurrentModificationException + List children = new ArrayList(this.root.getContent()); + + for(Content child : children){ + if(child instanceof Element){ + recursivelyRemoveEmptyChildren(this.root, (Element)child); + } + } + } + private void recursivelyRemoveEmptyChildren(Element grandparent, Element parent){ + //must make a copy to avoid ConcurrentModificationException + List childrenPreRemoval; + childrenPreRemoval = new ArrayList(parent.getContent()); + + //base case: the parent has no children + for(Content child : childrenPreRemoval){ + //recursive case: the parent has children + if(child instanceof Element){ + recursivelyRemoveEmptyChildren(parent, (Element)child); + } + } + + //if the parent node contains no children, remove it from the parent + List childrenPostRemoval = parent.getContent(); + if(childrenPostRemoval.isEmpty()){ + grandparent.removeContent(parent); + } + } /** * @return an xml String */ diff --git a/src/test/java/it/geosolutions/geoserver/rest/encoder/utils/XmlElementTest.java b/src/test/java/it/geosolutions/geoserver/rest/encoder/utils/XmlElementTest.java new file mode 100644 index 0000000..93751c0 --- /dev/null +++ b/src/test/java/it/geosolutions/geoserver/rest/encoder/utils/XmlElementTest.java @@ -0,0 +1,119 @@ +package it.geosolutions.geoserver.rest.encoder.utils; + +import java.io.IOException; +import java.io.StringReader; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.jdom.Document; +import org.jdom.Element; +import org.jdom.JDOMException; +import org.jdom.input.SAXBuilder; +import org.jdom.output.XMLOutputter; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.*; + +public class XmlElementTest { + + public XmlElementTest() { + } + + @BeforeClass + public static void setUpClass() { + } + + @AfterClass + public static void tearDownClass() { + } + + @Before + public void setUp() { + } + + @After + public void tearDown() { + } + + private XmlElement makeElement(String docString){ + Document doc; + SAXBuilder builder = new SAXBuilder(); + try { + doc = builder.build(new StringReader(docString)); + } catch (JDOMException ex) { + throw new RuntimeException(ex); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + Element root = doc.getRootElement(); + + return new XmlElement(root); + } + + private void assertEqualXml(String message, XmlElement expected, XmlElement actual){ + XMLOutputter out = new XMLOutputter(); + String expectedElementString = out.outputString(expected.getRoot()); + String actualElementString = out.outputString(actual.getRoot()); + assertEquals(message, expectedElementString, actualElementString); + } + + @Test + public void testRecursiveRemovalOnChildlessParent(){ + XmlElement root = makeElement(""); + root.recursivelyRemoveEmptyChildren(); + assertEqualXml("no child elements expected", makeElement(""), root); + } + + @Test + public void testRecursiveRemovalOfOneChild(){ + XmlElement root = makeElement(""); + root.recursivelyRemoveEmptyChildren(); + assertEqualXml("no child elements expected", makeElement(""), root); + } + + @Test + public void testRecursiveRemovalOfOneChildWithOneKeeper(){ + XmlElement root = makeElement("keep"); + root.recursivelyRemoveEmptyChildren(); + assertEqualXml("one child element expected", makeElement("keep"), root); + } + + @Test + public void testRecursiveRemovalOfOneParentAndOneChild() { + XmlElement root = makeElement(""); + root.recursivelyRemoveEmptyChildren(); + assertEqualXml("no child elements expected", makeElement(""), root); + } + + @Test + public void testRecursiveRemovalOfOneParentAndManyChildren() { + XmlElement root = makeElement(""); + root.recursivelyRemoveEmptyChildren(); + assertEqualXml("no child elements expected", makeElement(""), root); + } + + @Test + public void testRecursiveRemovalOfManyParentsWithOneChild() { + XmlElement root = makeElement(""); + root.recursivelyRemoveEmptyChildren(); + assertEqualXml("no child elements expected", makeElement(""), root); + } + + @Test + public void testRecursiveRemovalOfManyParentsAndManyChildren() { + XmlElement root = makeElement(""); + root.recursivelyRemoveEmptyChildren(); + assertEqualXml("no child elements expected", makeElement(""), root); + } + + @Test + public void testRecursiveRemovalOfManyParentsAndManyChildrenWithSomeKeepers() { + XmlElement root = makeElement("keepkeepkeepkeep"); + root.recursivelyRemoveEmptyChildren(); + assertEqualXml("only non-empty child elements should remain", makeElement("keepkeepkeepkeep"), root); + } + + +} \ No newline at end of file