OSDN Git Service

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