OSDN Git Service

use multi-catch.
[mikutoga/TogaGem.git] / src / main / java / jp / sfjp / mikutoga / typical / TypicalMorph.java
1 /*
2  * typical morph information
3  *
4  * License : The MIT License
5  * Copyright(c) 2011 MikuToga Partners
6  */
7
8 package jp.sfjp.mikutoga.typical;
9
10 import java.io.IOException;
11 import java.io.InputStream;
12 import java.util.ArrayList;
13 import java.util.Collections;
14 import java.util.EnumMap;
15 import java.util.List;
16 import java.util.Map;
17 import javax.xml.parsers.ParserConfigurationException;
18 import jp.sfjp.mikutoga.pmd.MorphType;
19 import org.w3c.dom.Element;
20 import org.w3c.dom.NodeList;
21 import org.xml.sax.SAXException;
22
23
24 /**
25  * 一般的な標準モーフに関する情報。
26  *
27  * <p>各モーフ情報はひとつ以上のプライマリ名(≒日本語名)と
28  * ゼロ個以上のグローバル名(≒英語名)を持つ。
29  *
30  * <p>選択基準は独断。
31  *
32  * <p>和英対訳はMMD Ver7.39の同梱モデルにほぼ準拠。
33  */
34 public final class TypicalMorph extends I18nAlias {
35
36     private static final Class<?> THISCLASS = TypicalMorph.class;
37     private static final String MORPH_XML = "resources/typicalMorph.xml";
38
39     private static final String ELEM_MORPHGROUP = "morphGroup";
40     private static final String ELEM_MORPH      = "morph";
41     private static final String ATTR_TYPE       = "type";
42     private static final String ELEM_PRIMARY    = "primary";
43     private static final String ELEM_GLOBAL     = "global";
44     private static final String ATTR_NAME       = "name";
45
46     private static final List<TypicalMorph> EMPTY = Collections.emptyList();
47
48     private static final Map<MorphType, List<TypicalMorph>> TYPED_MAP =
49             new EnumMap<>(MorphType.class);
50
51     private static final AliasMap<TypicalMorph> MORPH_ALIAS_MAP =
52             new AliasMap<>();
53
54
55     static{
56         InputStream is = THISCLASS.getResourceAsStream(MORPH_XML);
57
58         Element top;
59         try{
60             top = I18nAlias.loadXml(is);
61         }catch(ParserConfigurationException | SAXException | IOException e){
62             throw new ExceptionInInitializerError(e);
63         }
64
65         parse(top);
66
67         numbering();
68     }
69
70
71     private final MorphType type;
72
73
74     /**
75      * コンストラクタ。
76      *
77      * <p>各初期数が0以下の場合は、
78      * 状況に応じて伸長する連結リストが用意される。
79      *
80      * @param type モーフ種別
81      * @param primaryNum プライマリ名初期数。
82      * @param globalNum グローバル名初期数。
83      */
84     private TypicalMorph(MorphType type, int primaryNum, int globalNum){
85         super(primaryNum, globalNum);
86
87         this.type = type;
88
89         assert this.getClass() == THISCLASS;
90
91         return;
92     }
93
94
95     /**
96      * XML文書の最上位構造を解読する。
97      * @param top 最上位要素
98      */
99     private static void parse(Element top) {
100         NodeList groupList = top.getElementsByTagName(ELEM_MORPHGROUP);
101         int groupNo = groupList.getLength();
102         for(int idx = 0; idx < groupNo; idx++){
103             Element groupElem = (Element) groupList.item(idx);
104             parseGroup(groupElem);
105         }
106
107         // 必要に応じモーフ枠に不変空リスト登録
108         for(MorphType morphType : MorphType.values()){
109             if( ! TYPED_MAP.containsKey(morphType) ){
110                 TYPED_MAP.put(morphType, EMPTY);
111             }
112         }
113
114         return;
115     }
116
117     /**
118      * モーフグループ構造を解読する。
119      * @param groupElem morphGroup要素
120      */
121     private static void parseGroup(Element groupElem){
122         String typeAttr = groupElem.getAttribute(ATTR_TYPE);
123         MorphType morphType = MorphType.valueOf(typeAttr);
124
125         NodeList morphList = groupElem.getElementsByTagName(ELEM_MORPH);
126         int morphNo = morphList.getLength();
127         List<TypicalMorph> groupedList =
128                 new ArrayList<>(morphNo);
129
130         for(int idx = 0; idx < morphNo; idx++){
131             Element morphElem = (Element) morphList.item(idx);
132             TypicalMorph morph = parseMorph(morphElem, morphType);
133             groupedList.add(morph);
134             MORPH_ALIAS_MAP.addAlias(morph);
135         }
136
137         groupedList = Collections.unmodifiableList(groupedList);
138         TYPED_MAP.put(morphType, groupedList);
139
140         return;
141     }
142
143     /**
144      * morph要素を解読する。
145      * @param morphElem morph要素
146      * @param mtype モーフ種別
147      * @return モーフ情報
148      */
149     private static TypicalMorph parseMorph(Element morphElem,
150                                              MorphType mtype ){
151         NodeList primaryNodes = morphElem.getElementsByTagName(ELEM_PRIMARY);
152         NodeList globalNodes  = morphElem.getElementsByTagName(ELEM_GLOBAL);
153         int primaryNo = primaryNodes.getLength();
154         int globalNo  = globalNodes.getLength();
155
156         assert primaryNo > 0;
157
158         TypicalMorph morph = new TypicalMorph(mtype, primaryNo, globalNo);
159
160         for(int idx = 0; idx < primaryNo; idx++){
161             Element primaryElem = (Element) primaryNodes.item(idx);
162             String primaryName = primaryElem.getAttribute(ATTR_NAME);
163             morph.addPrimaryName(primaryName);
164         }
165
166         for(int idx = 0; idx < globalNo; idx++){
167             Element globalElem = (Element) globalNodes.item(idx);
168             String globalName = globalElem.getAttribute(ATTR_NAME);
169             morph.addGlobalName(globalName);
170         }
171
172         return morph;
173     }
174
175     /**
176      * 全モーフ情報に通し番号を付ける。
177      *
178      * <p>同一グループ内ではXMLでの定義順が反映される。
179      */
180     private static void numbering(){
181         int order = 0;
182         for(MorphType morphType : MorphType.values()){
183             for(TypicalMorph morph : TYPED_MAP.get(morphType)){
184                 morph.setOrderNo(order++);
185             }
186         }
187
188         return;
189     }
190
191     /**
192      * 種別ごとのモーフ情報不変リストを取得する。
193      * @param morphType モーフ種別
194      * @return モーフ情報不変リスト
195      */
196     public static List<TypicalMorph> getTypicalMorphList(
197             MorphType morphType ){
198         List<TypicalMorph> result = TYPED_MAP.get(morphType);
199         return result;
200     }
201
202     /**
203      * プライマリ名の合致するモーフ情報を返す。
204      * NFKCで正規化されたプライマリ名で検索される。
205      * @param primaryName プライマリ名
206      * @return モーフ情報。見つからなければnull
207      */
208     public static TypicalMorph findWithPrimary(String primaryName){
209         TypicalMorph result = MORPH_ALIAS_MAP.getAliasByPrimary(primaryName);
210         return result;
211     }
212
213     /**
214      * グローバル名の合致するモーフ情報を返す。
215      * NFKCで正規化されたグローバル名で検索される。
216      * @param globalName グローバル名
217      * @return モーフ情報。見つからなければnull
218      */
219     public static TypicalMorph findWithGlobal(String globalName){
220         TypicalMorph result = MORPH_ALIAS_MAP.getAliasByGlobal(globalName);
221         return result;
222     }
223
224     /**
225      * プライマリ名をグローバル名に変換する。
226      * @param primaryName プライマリ名
227      * @return グローバル名。見つからなければnull
228      */
229     public static String primary2global(String primaryName){
230         String globalName = MORPH_ALIAS_MAP.primary2global(primaryName);
231         return globalName;
232     }
233
234     /**
235      * グローバル名をプライマリ名へ変換する。
236      * @param globalName グローバル名
237      * @return プライマリ名。見つからなければnull
238      */
239     public static String global2primary(String globalName){
240         String primaryName = MORPH_ALIAS_MAP.global2primary(globalName);
241         return primaryName;
242     }
243
244
245     /**
246      * モーフ種別を返す。
247      * @return モーフ種別
248      */
249     public MorphType getMorphType(){
250         return this.type;
251     }
252
253 }