OSDN Git Service

suppress SimplifyBooleanReturns warning in PMD.
[mikutoga/TogaGem.git] / src / main / java / jp / sfjp / mikutoga / xml / DomUtils.java
1 /*
2  * XML DOM utilities
3  *
4  * License : The MIT License
5  * Copyright(c) 2010 MikuToga Partners
6  */
7
8 package jp.sfjp.mikutoga.xml;
9
10 import java.util.Iterator;
11 import java.util.LinkedList;
12 import java.util.List;
13 import java.util.NoSuchElementException;
14 import org.w3c.dom.Element;
15 import org.w3c.dom.Node;
16
17 /**
18  * DOMユーティリティ。
19  */
20 public final class DomUtils {
21
22     // 構文解析バグ回避。
23     private static final char BS_CHAR = (char) 0x005c;
24
25     /**
26      * 隠しコンストラクタ。
27      */
28     private DomUtils(){
29         super();
30         assert false;
31         throw new AssertionError();
32     }
33
34     /**
35      * 要素からxsd:string型属性値を読み取る。
36      * @param elem 要素
37      * @param attrName 属性名
38      * @return 文字列
39      * @throws TogaXmlException 属性値が見つからなかった。
40      */
41     public static String getStringAttr(Element elem, String attrName)
42             throws TogaXmlException{
43         if( ! elem.hasAttribute(attrName) ){
44             String message = "Attr:[" + attrName + "] "
45                     + "was not found in "
46                     + "Elem:[" + elem.getTagName()+"]";
47             throw new TogaXmlException(message);
48         }
49
50         String result;
51         try{
52             result = elem.getAttribute(attrName);
53         }catch(IllegalArgumentException e){
54             String message = "Invalid attribute form [" + attrName + "]";
55             throw new TogaXmlException(message, e);
56         }
57
58         return result;
59     }
60
61     /**
62      * 要素からxsd:boolean型属性値を読み取る。
63      * @param elem 要素
64      * @param attrName 属性名
65      * @return 真ならtrue
66      * @throws TogaXmlException 属性値が見つからなかった。
67      */
68     public static boolean getBooleanAttr(Element elem, String attrName)
69             throws TogaXmlException{
70         String value = getStringAttr(elem, attrName);
71
72         boolean result;
73         try{
74             result = DatatypeIo.parseBoolean(value);
75         }catch(IllegalArgumentException e){
76             String message =
77                     "Invalid boolean attribute form "
78                     + "[" + attrName + "][" + value + "]";
79             throw new TogaXmlException(message, e);
80         }
81
82         return result;
83     }
84
85     /**
86      * 要素からxsd:integer型属性値を読み取る。
87      * @param elem 要素
88      * @param attrName 属性名
89      * @return int値
90      * @throws TogaXmlException 属性値が見つからなかった。
91      */
92     public static int getIntegerAttr(Element elem, String attrName)
93             throws TogaXmlException{
94         String value = getStringAttr(elem, attrName);
95
96         int result;
97         try{
98             result = DatatypeIo.parseInt(value);
99         }catch(IllegalArgumentException e){
100             String message =
101                     "Invalid integer attribute form "
102                     + "[" + attrName + "][" + value + "]";
103             throw new TogaXmlException(message, e);
104         }
105
106         return result;
107     }
108
109     /**
110      * 要素からxsd:float型属性値を読み取る。
111      * @param elem 要素
112      * @param attrName 属性名
113      * @return float値
114      * @throws TogaXmlException 属性値が見つからなかった。
115      */
116     public static float getFloatAttr(Element elem, String attrName)
117             throws TogaXmlException{
118         String value = getStringAttr(elem, attrName);
119
120         float result;
121         try{
122             result = DatatypeIo.parseFloat(value);
123         }catch(IllegalArgumentException e){
124             String message =
125                     "Invalid float attribute form "
126                     + "[" + attrName + "][" + value + "]";
127             throw new TogaXmlException(message, e);
128         }
129
130         return result;
131     }
132
133     /**
134      * 要素から日本語Windows用ファイル名を属性値として読み取る。
135      * 念のため文字U+00A5は文字U-005Cに変換される。
136      * @param elem 要素
137      * @param attrName 属性名
138      * @return ファイル名
139      * @throws TogaXmlException 属性値が見つからなかった。
140      */
141     public static String getSjisFileNameAttr(Element elem, String attrName)
142             throws TogaXmlException{
143         String result;
144         try{
145             result = getStringAttr(elem, attrName);
146         }catch(IllegalArgumentException e){
147             String message =
148                     "Invalid winfile attribute form "
149                     + "[" + attrName + "]";
150             throw new TogaXmlException(message, e);
151         }
152
153         result = result.replace("" + '\u00a5', "" + BS_CHAR);
154
155         return result;
156     }
157
158     /**
159      * 指定された名前の子要素を1つだけ返す。
160      * @param parent 親要素
161      * @param tagName 子要素名
162      * @return 子要素
163      * @throws TogaXmlException 1つも見つからなかった
164      */
165     public static Element getChild(Element parent, String tagName)
166             throws TogaXmlException{
167         Element result = null;
168
169         for(Node node = parent.getFirstChild();
170             node != null;
171             node = node.getNextSibling() ){
172
173             if(node.getNodeType() != Node.ELEMENT_NODE) continue;
174             Element elem = (Element) node;
175
176             String elemTagName = elem.getTagName();
177             if( tagName.equals(elemTagName) ){
178                 result = elem;
179                 break;
180             }
181         }
182
183         if(result == null){
184             String message =
185                     "Elem:[" + tagName + "] was not found in "
186                     +"Elem:[" + parent.getTagName() + "]";
187             throw new TogaXmlException(message);
188         }
189
190         return result;
191     }
192
193     /**
194      * 親要素が指定された名前の子要素を持つか判定する。
195      * @param parent 親要素
196      * @param tagName 子要素名
197      * @return 指定名の子要素が存在すればtrue
198      */
199     public static boolean hasChild(Element parent, String tagName){
200         for(Node node = parent.getFirstChild();
201             node != null;
202             node = node.getNextSibling() ){
203
204             if(node.getNodeType() != Node.ELEMENT_NODE) continue;
205             Element elem = (Element) node;
206
207             String elemTagName = elem.getTagName();
208             if( tagName.equals(elemTagName) ) return true;
209         }
210
211         return false;
212     }
213
214     /**
215      * 指定された名前の子要素のリストを返す。
216      * @param parent 親要素
217      * @param childTag 子要素名
218      * @return 子要素のリスト
219      */
220     public static List<Element> getChildList(Element parent,
221                                                String childTag){
222         List<Element> result = new LinkedList<>();
223
224         for(Node node = parent.getFirstChild();
225             node != null;
226             node = node.getNextSibling() ){
227
228             if(node.getNodeType() != Node.ELEMENT_NODE) continue;
229             Element elem = (Element) node;
230
231             String tagName = elem.getTagName();
232             if( ! childTag.equals(tagName) ) continue;
233
234             result.add(elem);
235         }
236
237         return result;
238     }
239
240     /**
241      * 指定された名前の子要素の列挙子を返す。
242      * @param parent 親要素
243      * @param childTag 子要素名
244      * @return 子要素の列挙子
245      */
246     public static Iterator<Element> getChildIterator(Element parent,
247                                                        String childTag){
248         Element firstElem;
249         try{
250             firstElem = getChild(parent, childTag);
251         }catch(TogaXmlException e){
252             firstElem = null;
253         }
254
255         Iterator<Element> result = new ElemIterator(firstElem);
256
257         return result;
258     }
259
260     /**
261      * 指定された名前の子要素のforeachを返す。
262      * @param parent 親要素
263      * @param childTag 子要素名
264      * @return 子要素のforeach
265      */
266     public static Iterable<Element> getEachChild(Element parent,
267                                                    String childTag){
268         final Iterator<Element> iterator = getChildIterator(parent, childTag);
269         Iterable<Element> result = new Iterable<Element>(){
270             @Override
271             public Iterator<Element> iterator(){
272                 return iterator;
273             }
274         };
275         return result;
276     }
277
278     /**
279      * 要素の次の要素を返す。
280      * @param elem 要素
281      * @return 次の要素。なければnull
282      */
283     public static Element nextElement(Element elem){
284         Node nextNode = elem;
285         for(;;){
286             nextNode = nextNode.getNextSibling();
287             if(nextNode == null) break;
288             if(nextNode.getNodeType() == Node.ELEMENT_NODE){
289                 break;
290             }
291         }
292
293         return (Element) nextNode;
294     }
295
296     /**
297      * 同じ要素名を持つ次の要素を返す。
298      * @param elem 要素
299      * @return 次の要素。なければnull
300      */
301     public static Element nextNamedElement(Element elem){
302         String tagName = elem.getTagName();
303         Element nextElem = elem;
304         for(;;){
305             nextElem = nextElement(nextElem);
306             if(nextElem == null) break;
307             if(tagName.equals(nextElem.getTagName())) break;
308         }
309
310         return nextElem;
311     }
312
313     /**
314      * 同じ親要素と同じ要素名を持つ兄弟要素を列挙する列挙子。
315      */
316     private static final class ElemIterator implements Iterator<Element> {
317         private Element next;
318
319         /**
320          * コンストラクタ。
321          * @param elem 最初の要素。nullを指定すれば空列挙子となる。
322          */
323         ElemIterator(Element elem){
324             super();
325             this.next = elem;
326         }
327
328         /**
329          * {@inheritDoc}
330          * @return {@inheritDoc}
331          */
332         @Override
333         public boolean hasNext(){
334             if(this.next == null) return false;
335             return true;
336         }
337
338         /**
339          * {@inheritDoc}
340          * @return {@inheritDoc}
341          * @throws NoSuchElementException {@inheritDoc}
342          */
343         @Override
344         public Element next() throws NoSuchElementException{
345             if(this.next == null) throw new NoSuchElementException();
346             Element result = this.next;
347             this.next = nextNamedElement(this.next);
348             return result;
349         }
350
351         /**
352          * {@inheritDoc}
353          * ※ 未サポート。
354          */
355         @Override
356         public void remove(){
357             throw new UnsupportedOperationException();
358         }
359
360     }
361
362 }