OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Rev 73 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 73 Rev 83
1
/*
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 * 
3
 * 
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
5
 * 
5
 * 
6
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
6
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
7
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
7
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
8
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
8
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
9
 * language governing permissions and limitations under the License.
9
 * language governing permissions and limitations under the License.
10
 * 
10
 * 
11
 * When distributing the software, include this License Header Notice in each file.
11
 * When distributing the software, include this License Header Notice in each file.
12
 */
12
 */
13
 
13
 
14
 package org.openconcerto.xml;
14
 package org.openconcerto.xml;
15
 
15
 
16
import org.openconcerto.utils.CollectionUtils;
16
import org.openconcerto.utils.CollectionUtils;
17
import org.openconcerto.xml.Step.Axis;
17
import org.openconcerto.xml.Step.Axis;
18
 
18
 
19
import java.util.ArrayList;
19
import java.util.ArrayList;
20
import java.util.Arrays;
20
import java.util.Arrays;
21
import java.util.Collections;
21
import java.util.Collections;
22
import java.util.Iterator;
22
import java.util.Iterator;
23
import java.util.List;
23
import java.util.List;
24
 
24
 
25
import org.jdom.Attribute;
25
import org.jdom.Attribute;
26
import org.jdom.Element;
26
import org.jdom.Element;
27
import org.jdom.filter.Filter;
27
import org.jdom.filter.Filter;
28
import org.jdom.xpath.XPath;
28
import org.jdom.xpath.XPath;
29
 
29
 
30
/**
30
/**
31
 * Like an {@link XPath} with less features but a greater speed. Thread-safe if its {@link Step
31
 * Like an {@link XPath} with less features but a greater speed. Thread-safe if its {@link Step
32
 * steps} are.
32
 * steps} are.
33
 * 
33
 * 
34
 * @author Sylvain CUAZ
34
 * @author Sylvain CUAZ
35
 * 
35
 * 
36
 * @param <T> type of result.
36
 * @param <T> type of result.
37
 */
37
 */
38
public final class SimpleXMLPath<T> {
38
public final class SimpleXMLPath<T> {
39
 
39
 
-
 
40
    private static final SimpleXMLPath<Attribute> ALL_ATTRIBUTES = allAttributes(null, null);
-
 
41
    private static final SimpleXMLPath<Element> ALL_ELEMENTS = allElements(null, null);
-
 
42
 
40
    public static <T> SimpleXMLPath<T> create(final List<Step<?>> steps, final Step<T> lastStep) {
43
    public static <T> SimpleXMLPath<T> create(final List<Step<?>> steps, final Step<T> lastStep) {
41
        return new SimpleXMLPath<T>(Collections.unmodifiableList(new ArrayList<Step<?>>(steps)), lastStep);
44
        return new SimpleXMLPath<T>(Collections.unmodifiableList(new ArrayList<Step<?>>(steps)), lastStep);
42
    }
45
    }
43
 
46
 
44
    public static <T> SimpleXMLPath<T> create(final Step<T> lastStep) {
47
    public static <T> SimpleXMLPath<T> create(final Step<T> lastStep) {
45
        return new SimpleXMLPath<T>(Collections.<Step<?>> emptyList(), lastStep);
48
        return new SimpleXMLPath<T>(Collections.<Step<?>> emptyList(), lastStep);
46
    }
49
    }
47
 
50
 
48
    public static <T> SimpleXMLPath<T> create(final Step<?> first, final Step<T> lastStep) {
51
    public static <T> SimpleXMLPath<T> create(final Step<?> first, final Step<T> lastStep) {
49
        return new SimpleXMLPath<T>(Collections.<Step<?>> singletonList(first), lastStep);
52
        return new SimpleXMLPath<T>(Collections.<Step<?>> singletonList(first), lastStep);
50
    }
53
    }
51
 
54
 
52
    public static <T> SimpleXMLPath<T> create(final Step<?> first, final Step<?> second, final Step<T> lastStep) {
55
    public static <T> SimpleXMLPath<T> create(final Step<?> first, final Step<?> second, final Step<T> lastStep) {
53
        return new SimpleXMLPath<T>(Arrays.<Step<?>> asList(first, second), lastStep);
56
        return new SimpleXMLPath<T>(Arrays.<Step<?>> asList(first, second), lastStep);
54
    }
57
    }
55
 
58
 
56
    /**
59
    /**
-
 
60
     * Create a path searching for all descendant attributes. The returned instance is immutable.
-
 
61
     * 
-
 
62
     * @return a path searching attributes in all {@link Axis#descendantOrSelf} elements.
-
 
63
     */
-
 
64
    public static SimpleXMLPath<Attribute> allAttributes() {
-
 
65
        return ALL_ATTRIBUTES;
-
 
66
    }
-
 
67
 
-
 
68
    /**
57
     * Create a path searching for all descendant attributes with the passed name and namespace.
69
     * Create a path searching for all descendant attributes with the passed name and namespace.
58
     * I.e. in XPath this would be ".//@ns:name".
70
     * I.e. in XPath this would be ".//@ns:name". The returned instance is immutable.
59
     * 
71
     * 
60
     * @param name the name of attributes.
72
     * @param name the name of attributes.
61
     * @param ns the namespace of attributes.
73
     * @param ns the namespace of attributes.
62
     * @return a path searching attributes in all {@link Axis#descendantOrSelf} elements.
74
     * @return a path searching attributes in all {@link Axis#descendantOrSelf} elements.
63
     */
75
     */
64
    public static SimpleXMLPath<Attribute> allAttributes(final String name, final String ns) {
76
    public static SimpleXMLPath<Attribute> allAttributes(final String name, final String ns) {
65
        return create(Step.createElementStep(Axis.descendantOrSelf, null), Step.createAttributeStep(name, ns));
77
        return create(Step.createElementStep(Axis.descendantOrSelf, null), Step.createAttributeStep(name, ns));
66
    }
78
    }
67
 
79
 
68
    /**
80
    /**
-
 
81
     * Create a path searching for all descendant elements. The returned instance is immutable.
-
 
82
     * 
-
 
83
     * @return a path searching all {@link Axis#descendantOrSelf} elements.
-
 
84
     */
-
 
85
    public static SimpleXMLPath<Element> allElements() {
-
 
86
        return ALL_ELEMENTS;
-
 
87
    }
-
 
88
 
-
 
89
    /**
69
     * Create a path searching for all descendant elements with the passed name and namespace. I.e.
90
     * Create a path searching for all descendant elements with the passed name and namespace. I.e.
70
     * in XPath this would be ".//ns:name".
91
     * in XPath this would be ".//ns:name". The returned instance is immutable.
71
     * 
92
     * 
72
     * @param name the name of elements.
93
     * @param name the name of elements.
73
     * @param ns the namespace of elements.
94
     * @param ns the namespace of elements.
74
     * @return a path searching all {@link Axis#descendantOrSelf} elements.
95
     * @return a path searching all {@link Axis#descendantOrSelf} elements.
75
     */
96
     */
76
    public static SimpleXMLPath<Element> allElements(final String name, final String ns) {
97
    public static SimpleXMLPath<Element> allElements(final String name, final String ns) {
77
        return create(Step.createElementStep(Axis.descendantOrSelf, name, ns));
98
        return create(Step.createElementStep(Axis.descendantOrSelf, name, ns));
78
    }
99
    }
79
 
100
 
80
    private final List<Step<?>> items;
101
    private final List<Step<?>> items;
81
    private final Step<T> lastItem;
102
    private final Step<T> lastItem;
82
 
103
 
83
    // private since we don't copy steps
104
    // private since we don't copy steps
84
    private SimpleXMLPath(final List<Step<?>> steps, Step<T> lastStep) {
105
    private SimpleXMLPath(final List<Step<?>> steps, Step<T> lastStep) {
85
        this.lastItem = lastStep;
106
        this.lastItem = lastStep;
86
        this.items = steps;
107
        this.items = steps;
87
    }
108
    }
88
 
109
 
89
    // return Element or Attribute
110
    // return Element or Attribute
90
    public final T selectSingleNode(final Object n) {
111
    public final T selectSingleNode(final Object n) {
91
        return selectSingleNode(n, this.items);
112
        return selectSingleNode(n, this.items);
92
    }
113
    }
93
 
114
 
94
    private final T selectSingleNode(final Object currentNode, List<Step<?>> steps) {
115
    private final T selectSingleNode(final Object currentNode, List<Step<?>> steps) {
95
        final int size = steps.size();
116
        final int size = steps.size();
96
        if (size > 0) {
117
        if (size > 0) {
97
            final Step<?> currentStep = steps.get(0);
118
            final Step<?> currentStep = steps.get(0);
98
 
119
 
99
            final List<?> nextNodes = currentStep.nextNodes(Node.get(currentNode), currentNode);
120
            final List<?> nextNodes = currentStep.nextNodes(Node.get(currentNode), currentNode);
100
            // MAYBE add an index argument instead of creating a sublist
121
            // MAYBE add an index argument instead of creating a sublist
101
            final List<Step<?>> nextSteps = steps.subList(1, size);
122
            final List<Step<?>> nextSteps = steps.subList(1, size);
102
            final int stop = nextNodes.size();
123
            final int stop = nextNodes.size();
103
            for (int i = 0; i < stop; i++) {
124
            for (int i = 0; i < stop; i++) {
104
                final T finalNode = this.selectSingleNode(nextNodes.get(i), nextSteps);
125
                final T finalNode = this.selectSingleNode(nextNodes.get(i), nextSteps);
105
                if (finalNode != null)
126
                if (finalNode != null)
106
                    return finalNode;
127
                    return finalNode;
107
            }
128
            }
108
            return null;
129
            return null;
109
        } else {
130
        } else {
110
            return CollectionUtils.getFirst(this.lastItem.nextNodes(Node.get(currentNode), currentNode));
131
            return CollectionUtils.getFirst(this.lastItem.nextNodes(Node.get(currentNode), currentNode));
111
        }
132
        }
112
    }
133
    }
113
 
134
 
114
    public final List<T> selectNodes(final Object n) {
135
    public final List<T> selectNodes(final Object n) {
115
        return this.selectNodes(Collections.singletonList(n));
136
        return this.selectNodes(Collections.singletonList(n));
116
    }
137
    }
117
 
138
 
118
    public final List<T> selectNodes(final List<?> nodes) {
139
    public final List<T> selectNodes(final List<?> nodes) {
119
        List<?> currentNodes = nodes;
140
        List<?> currentNodes = nodes;
120
        final int stop = this.items.size();
141
        final int stop = this.items.size();
121
        for (int i = 0; i < stop; i++) {
142
        for (int i = 0; i < stop; i++) {
122
            final Step<?> currentStep = this.items.get(i);
143
            final Step<?> currentStep = this.items.get(i);
123
 
144
 
124
            final List<?> nextNodes = currentStep.nextNodes(currentNodes);
145
            final List<?> nextNodes = currentStep.nextNodes(currentNodes);
125
            if (nextNodes.isEmpty())
146
            if (nextNodes.isEmpty())
126
                return Collections.emptyList();
147
                return Collections.emptyList();
127
            else
148
            else
128
                currentNodes = nextNodes;
149
                currentNodes = nextNodes;
129
 
150
 
130
        }
151
        }
131
        return this.lastItem.nextNodes(currentNodes);
152
        return this.lastItem.nextNodes(currentNodes);
132
    }
153
    }
133
 
154
 
134
    // encapsulate differences about JDOM nodes
155
    // encapsulate differences about JDOM nodes
135
    static abstract class Node<T> {
156
    static abstract class Node<T> {
136
 
157
 
137
        static final Node<Element> elem = new ElementNode();
158
        static final Node<Element> elem = new ElementNode();
138
        static final Node<Attribute> attr = new AttributeNode();
159
        static final Node<Attribute> attr = new AttributeNode();
139
 
160
 
140
        @SuppressWarnings("unchecked")
161
        @SuppressWarnings("unchecked")
141
        public static <TT> Node<TT> get(TT o) {
162
        public static <TT> Node<TT> get(TT o) {
142
            if (o instanceof Attribute)
163
            if (o instanceof Attribute)
143
                return (Node<TT>) attr;
164
                return (Node<TT>) attr;
144
            else if (o instanceof Element)
165
            else if (o instanceof Element)
145
                return (Node<TT>) elem;
166
                return (Node<TT>) elem;
146
            else
167
            else
147
                throw new IllegalArgumentException("unknown Node: " + o);
168
                throw new IllegalArgumentException("unknown Node: " + o);
148
        }
169
        }
149
 
170
 
150
        @SuppressWarnings("unchecked")
171
        @SuppressWarnings("unchecked")
151
        public static <TT> Node<TT> get(Class<TT> clazz) {
172
        public static <TT> Node<TT> get(Class<TT> clazz) {
152
            if (clazz == Attribute.class)
173
            if (clazz == Attribute.class)
153
                return (Node<TT>) attr;
174
                return (Node<TT>) attr;
154
            else if (clazz == Element.class)
175
            else if (clazz == Element.class)
155
                return (Node<TT>) elem;
176
                return (Node<TT>) elem;
156
            else
177
            else
157
                throw new IllegalArgumentException("unknown Node: " + clazz);
178
                throw new IllegalArgumentException("unknown Node: " + clazz);
158
        }
179
        }
159
 
180
 
160
        public abstract <S> void nextNodes(final List<S> res, final T node, final Step<S> step);
181
        public abstract <S> void nextNodes(final List<S> res, final T node, final Step<S> step);
161
 
182
 
162
        // viva jdom who doesn't have a common interface for getName() and getNS()
183
        // viva jdom who doesn't have a common interface for getName() and getNS()
163
        abstract T filter(final T elem, final String name, final String ns);
184
        abstract T filter(final T elem, final String name, final String ns);
164
 
185
 
165
        @Override
186
        @Override
166
        public final String toString() {
187
        public final String toString() {
167
            return this.getClass().getSimpleName();
188
            return this.getClass().getSimpleName();
168
        }
189
        }
169
    }
190
    }
170
 
191
 
171
    static class AttributeNode extends Node<Attribute> {
192
    static class AttributeNode extends Node<Attribute> {
172
 
193
 
173
        @Override
194
        @Override
174
        public <S> void nextNodes(final List<S> res, final Attribute node, final Step<S> step) {
195
        public <S> void nextNodes(final List<S> res, final Attribute node, final Step<S> step) {
175
            if (step.getAxis() == Axis.ancestor) {
196
            if (step.getAxis() == Axis.ancestor) {
176
                step.add(node.getParent(), res);
197
                step.add(node.getParent(), res);
177
            } else
198
            } else
178
                throw new IllegalArgumentException(this + " cannot take the passed step: " + step);
199
                throw new IllegalArgumentException(this + " cannot take the passed step: " + step);
179
        }
200
        }
180
 
201
 
181
        @Override
202
        @Override
182
        Attribute filter(Attribute elem, String name, String ns) {
203
        Attribute filter(Attribute elem, String name, String ns) {
183
            if (elem == null)
204
            if (elem == null)
184
                return null;
205
                return null;
185
            if (name != null && !name.equals(elem.getName()))
206
            if (name != null && !name.equals(elem.getName()))
186
                return null;
207
                return null;
187
            if (ns != null && !ns.equals(elem.getNamespacePrefix()))
208
            if (ns != null && !ns.equals(elem.getNamespacePrefix()))
188
                return null;
209
                return null;
189
            return elem;
210
            return elem;
190
        }
211
        }
191
    }
212
    }
192
 
213
 
193
    static class ElementNode extends Node<Element> {
214
    static class ElementNode extends Node<Element> {
194
 
215
 
195
        @SuppressWarnings("unchecked")
216
        @SuppressWarnings("unchecked")
196
        @Override
217
        @Override
197
        public <S> void nextNodes(final List<S> res, final Element node, final Step<S> step) {
218
        public <S> void nextNodes(final List<S> res, final Element node, final Step<S> step) {
198
            final Axis axis = step.getAxis();
219
            final Axis axis = step.getAxis();
199
            if (axis == Axis.ancestor) {
220
            if (axis == Axis.ancestor) {
200
                step.add(node.getParent(), res);
221
                step.add(node.getParent(), res);
201
            } else if (axis == Axis.attribute) {
222
            } else if (axis == Axis.attribute) {
202
                final List<?> attributes = node.getAttributes();
223
                final List<?> attributes = node.getAttributes();
203
                final int stop = attributes.size();
224
                final int stop = attributes.size();
204
                for (int i = 0; i < stop; i++) {
225
                for (int i = 0; i < stop; i++) {
205
                    step.add(attributes.get(i), res);
226
                    step.add(attributes.get(i), res);
206
                }
227
                }
207
            } else if (axis == Axis.child) {
228
            } else if (axis == Axis.child) {
208
                // jdom : traversal through the List is best done with a Iterator
229
                // jdom : traversal through the List is best done with a Iterator
209
                for (final Object o : node.getChildren()) {
230
                for (final Object o : node.getChildren()) {
210
                    step.add(o, res);
231
                    step.add(o, res);
211
                }
232
                }
212
            } else if (axis == Axis.descendantOrSelf) {
233
            } else if (axis == Axis.descendantOrSelf) {
213
                step.add(node, res);
234
                step.add(node, res);
214
                final Iterator<S> iter = node.getDescendants(new Filter() {
235
                final Iterator<S> iter = node.getDescendants(new Filter() {
215
                    @Override
236
                    @Override
216
                    public boolean matches(Object obj) {
237
                    public boolean matches(Object obj) {
217
                        if (!(obj instanceof Element))
238
                        if (!(obj instanceof Element))
218
                            return false;
239
                            return false;
219
                        return step.evaluate(obj) != null;
240
                        return step.evaluate(obj) != null;
220
                    }
241
                    }
221
                });
242
                });
222
                while (iter.hasNext()) {
243
                while (iter.hasNext()) {
223
                    res.add(iter.next());
244
                    res.add(iter.next());
224
                }
245
                }
225
            } else
246
            } else
226
                throw new IllegalArgumentException(this + " cannot take the passed step: " + axis);
247
                throw new IllegalArgumentException(this + " cannot take the passed step: " + axis);
227
        }
248
        }
228
 
249
 
229
        @Override
250
        @Override
230
        Element filter(Element elem, String name, String ns) {
251
        Element filter(Element elem, String name, String ns) {
231
            if (elem == null)
252
            if (elem == null)
232
                return null;
253
                return null;
233
            if (name != null && !name.equals(elem.getName()))
254
            if (name != null && !name.equals(elem.getName()))
234
                return null;
255
                return null;
235
            if (ns != null && !ns.equals(elem.getNamespacePrefix()))
256
            if (ns != null && !ns.equals(elem.getNamespacePrefix()))
236
                return null;
257
                return null;
237
            return elem;
258
            return elem;
238
        }
259
        }
239
    }
260
    }
240
}
261
}