View Javadoc
1   /**
2    * This file Copyright (c) 2003-2015 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.importexport.filters;
35  
36  import java.util.ArrayList;
37  import java.util.List;
38  
39  import org.slf4j.Logger;
40  import org.slf4j.LoggerFactory;
41  import org.xml.sax.Attributes;
42  import org.xml.sax.SAXException;
43  import org.xml.sax.XMLReader;
44  import org.xml.sax.helpers.AttributesImpl;
45  import org.xml.sax.helpers.XMLFilterImpl;
46  
47  
48  /**
49   * A base abstract filter that can be sub-classed in order to easily implement removal of properties based on their
50   * name/content.
51   */
52  public abstract class SkipNodePropertyFilter extends XMLFilterImpl {
53  
54      protected Logger log = LoggerFactory.getLogger(getClass());
55  
56      protected String lastNodeName;
57  
58      protected boolean skipProperty;
59  
60      protected boolean invalue;
61  
62      private List<BufferedElement> elementBuffer = new ArrayList<BufferedElement>();
63  
64      /**
65       * Instantiates a new filter.
66       *
67       * @param parent wrapped XMLReader
68       */
69      public SkipNodePropertyFilter(XMLReader parent) {
70          super(parent);
71      }
72  
73      /**
74       * {@inheritDoc}
75       */
76      @Override
77      public void endElement(String uri, String localName, String qName) throws SAXException {
78  
79          if (skipProperty) {
80              if ("sv:property".equals(qName)) {
81                  skipProperty = false;
82                  invalue = false;
83                  elementBuffer.clear();
84              }
85              return;
86          }
87  
88          super.endElement(uri, localName, qName);
89      }
90  
91      /**
92       * {@inheritDoc}
93       */
94      @Override
95      public void characters(char[] ch, int start, int length) throws SAXException {
96          if (!skipProperty) {
97              super.characters(ch, start, length);
98          } else {
99              if (invalue) {
100                 invalue = false;
101                 // Arrays.copyOfRange(ch, start, start + length)
102                 char[] range = new char[length];
103                 System.arraycopy(ch, start, range, 0, length);
104                 String textContent = new String(range);
105 
106                 // skip only if filter() say so
107                 boolean skip = filter(textContent, lastNodeName);
108 
109                 if (!skip) {
110                     while (!elementBuffer.isEmpty()) {
111                         BufferedElement be = elementBuffer.remove(0);
112                         super.startElement(be.getUri(), be.getLocalName(), be.getQName(), be.getAtts());
113                     }
114                     super.characters(ch, start, length);
115                     skipProperty = false;
116                 }
117             }
118 
119         }
120     }
121 
122     /**
123      * {@inheritDoc}
124      */
125     @Override
126     public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
127 
128         String svname = atts.getValue("sv:name");
129         if ("sv:node".equals(qName)) {
130             lastNodeName = svname;
131         } else if ("sv:property".equals(qName) && (getFilteredPropertyName().equals(svname))) {
132             elementBuffer.add(new BufferedElement(uri, localName, qName, new AttributesImpl(atts)));
133 
134             skipProperty = true;
135             invalue = false;
136         } else if (skipProperty && "sv:value".equals(qName)) {
137             elementBuffer.add(new BufferedElement(uri, localName, qName, new AttributesImpl(atts)));
138             invalue = true;
139         }
140 
141         if (skipProperty) {
142             return;
143         }
144         super.startElement(uri, localName, qName, atts);
145 
146     }
147 
148     /**
149      * Implement this method to specify the name of the property you want to filter.
150      *
151      * @return filtered property name
152      */
153     protected abstract String getFilteredPropertyName();
154 
155     /**
156      * Implement this method to specificy if a given property (given its value and the parent node name) should be
157      * removed.
158      *
159      * @param propertyValue property value
160      * @param parentNodeName parent node name
161      * @return <code>true</code> if this property should be removed
162      */
163     protected abstract boolean filter(String propertyValue, String parentNodeName);
164 
165     /**
166      * Temporary element storage node.
167      */
168     public static class BufferedElement {
169 
170         private String uri;
171 
172         private String localName;
173 
174         private String qName;
175 
176         private Attributes atts;
177 
178         public BufferedElement(String uri, String localName, String qName, Attributes atts) {
179             this.atts = atts;
180             this.localName = localName;
181             this.qName = qName;
182             this.uri = uri;
183         }
184 
185         /**
186          * Returns the uri.
187          *
188          * @return the uri
189          */
190         public String getUri() {
191             return uri;
192         }
193 
194         /**
195          * Sets the uri.
196          *
197          * @param uri the uri to set
198          */
199         public void setUri(String uri) {
200             this.uri = uri;
201         }
202 
203         /**
204          * Returns the localName.
205          *
206          * @return the localName
207          */
208         public String getLocalName() {
209             return localName;
210         }
211 
212         /**
213          * Sets the localName.
214          *
215          * @param localName the localName to set
216          */
217         public void setLocalName(String localName) {
218             this.localName = localName;
219         }
220 
221         /**
222          * Returns the qName.
223          *
224          * @return the qName
225          */
226         public String getQName() {
227             return qName;
228         }
229 
230         /**
231          * Sets the qName.
232          *
233          * @param name the qName to set
234          */
235         public void setQName(String name) {
236             qName = name;
237         }
238 
239         /**
240          * Returns the atts.
241          *
242          * @return the atts
243          */
244         public Attributes getAtts() {
245             return atts;
246         }
247 
248         /**
249          * Sets the atts.
250          *
251          * @param atts the atts to set
252          */
253         public void setAtts(Attributes atts) {
254             this.atts = atts;
255         }
256     }
257 }