View Javadoc
1   /**
2    * This file Copyright (c) 2003-2014 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   * @author fgiust
52   * @version $Revision$ ($Author$)
53   */
54  public abstract class SkipNodePropertyFilter extends XMLFilterImpl {
55  
56      /**
57       * Logger.
58       */
59      protected Logger log = LoggerFactory.getLogger(getClass());
60  
61      protected String lastNodeName;
62  
63      protected boolean skipProperty;
64  
65      protected boolean invalue;
66  
67      private List<BufferedElement> elementBuffer = new ArrayList<BufferedElement>();
68  
69      /**
70       * Instantiates a new filter.
71       * @param parent wrapped XMLReader
72       */
73      public SkipNodePropertyFilter(XMLReader parent) {
74          super(parent);
75      }
76  
77      /**
78       * {@inheritDoc}
79       */
80      @Override
81      public void endElement(String uri, String localName, String qName) throws SAXException {
82  
83          if (skipProperty) {
84              if ("sv:property".equals(qName)) {
85                  skipProperty = false;
86                  invalue = false;
87                  elementBuffer.clear();
88              }
89              return;
90          }
91  
92          super.endElement(uri, localName, qName);
93      }
94  
95      /**
96       * {@inheritDoc}
97       */
98      @Override
99      public void characters(char[] ch, int start, int length) throws SAXException {
100         if (!skipProperty) {
101             super.characters(ch, start, length);
102         }
103         else {
104             if (invalue) {
105                 invalue = false;
106                 // Arrays.copyOfRange(ch, start, start + length)
107                 char[] range = new char[length];
108                 System.arraycopy(ch, start, range, 0, length);
109                 String textContent = new String(range);
110 
111                 // skip only if filter() say so
112                 boolean skip = filter(textContent, lastNodeName);
113 
114                 if (!skip) {
115                     while (!elementBuffer.isEmpty()) {
116                         BufferedElement be = elementBuffer.remove(0);
117                         super.startElement(be.getUri(), be.getLocalName(), be.getQName(), be.getAtts());
118                     }
119                     super.characters(ch, start, length);
120                     skipProperty = false;
121                 }
122             }
123 
124         }
125     }
126 
127     /**
128      * {@inheritDoc}
129      */
130     @Override
131     public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
132 
133         String svname = atts.getValue("sv:name");
134         if ("sv:node".equals(qName)) {
135             lastNodeName = svname;
136         }
137         else if ("sv:property".equals(qName) && (getFilteredPropertyName().equals(svname))) {
138             elementBuffer.add(new BufferedElement(uri, localName, qName, new AttributesImpl(atts)));
139 
140             skipProperty = true;
141             invalue = false;
142         }
143         else if (skipProperty && "sv:value".equals(qName)) {
144             elementBuffer.add(new BufferedElement(uri, localName, qName, new AttributesImpl(atts)));
145             invalue = true;
146         }
147 
148         if (skipProperty) {
149             return;
150         }
151         super.startElement(uri, localName, qName, atts);
152 
153     }
154 
155     /**
156      * Implement this method to specify the name of the property you want to filter.
157      * @return filtered property name
158      */
159     protected abstract String getFilteredPropertyName();
160 
161     /**
162      * Implement this method to specificy if a given property (given its value and the parent node name) should be
163      * removed.
164      * @param propertyValue property value
165      * @param parentNodeName parent node name
166      * @return <code>true</code> if this property should be removed
167      */
168     protected abstract boolean filter(String propertyValue, String parentNodeName);
169 
170     /**
171      * Temporary element storage node.
172      */
173     public static class BufferedElement {
174 
175         private String uri;
176 
177         private String localName;
178 
179         private String qName;
180 
181         private Attributes atts;
182 
183         /**
184          * @param atts
185          * @param localName
186          * @param name
187          * @param uri
188          */
189         public BufferedElement(String uri, String localName, String qName, Attributes atts) {
190             this.atts = atts;
191             this.localName = localName;
192             this.qName = qName;
193             this.uri = uri;
194         }
195 
196         /**
197          * Returns the uri.
198          * @return the uri
199          */
200         public String getUri() {
201             return uri;
202         }
203 
204         /**
205          * Sets the uri.
206          * @param uri the uri to set
207          */
208         public void setUri(String uri) {
209             this.uri = uri;
210         }
211 
212         /**
213          * Returns the localName.
214          * @return the localName
215          */
216         public String getLocalName() {
217             return localName;
218         }
219 
220         /**
221          * Sets the localName.
222          * @param localName the localName to set
223          */
224         public void setLocalName(String localName) {
225             this.localName = localName;
226         }
227 
228         /**
229          * Returns the qName.
230          * @return the qName
231          */
232         public String getQName() {
233             return qName;
234         }
235 
236         /**
237          * Sets the qName.
238          * @param name the qName to set
239          */
240         public void setQName(String name) {
241             qName = name;
242         }
243 
244         /**
245          * Returns the atts.
246          * @return the atts
247          */
248         public Attributes getAtts() {
249             return atts;
250         }
251 
252         /**
253          * Sets the atts.
254          * @param atts the atts to set
255          */
256         public void setAtts(Attributes atts) {
257             this.atts = atts;
258         }
259     }
260 }