OSDN Git Service

modify whitespaces.
[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, List<TypicalMorph>>(MorphType.class);
50
51     private static final AliasMap<TypicalMorph> MORPH_ALIAS_MAP =
52             new AliasMap<TypicalMorph>();
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 e){
62             throw new ExceptionInInitializerError(e);
63         }catch(SAXException e){
64             throw new ExceptionInInitializerError(e);
65         }catch(IOException e){
66             throw new ExceptionInInitializerError(e);
67         }
68
69         parse(top);
70
71         numbering();
72     }
73
74
75     private final MorphType type;
76
77
78     /**
79      * コンストラクタ。
80      *
81      * <p>各初期数が0以下の場合は、
82      * 状況に応じて伸長する連結リストが用意される。
83      *
84      * @param type モーフ種別
85      * @param primaryNum プライマリ名初期数。
86      * @param globalNum グローバル名初期数。
87      */
88     private TypicalMorph(MorphType type, int primaryNum, int globalNum){
89         super(primaryNum, globalNum);
90
91         this.type = type;
92
93         assert this.getClass() == THISCLASS;
94
95         return;
96     }
97
98
99     /**
100      * XML文書の最上位構造を解読する。
101      * @param top 最上位要素
102      */
103     private static void parse(Element top) {
104         NodeList groupList = top.getElementsByTagName(ELEM_MORPHGROUP);
105         int groupNo = groupList.getLength();
106         for(int idx = 0; idx < groupNo; idx++){
107             Element groupElem = (Element) groupList.item(idx);
108             parseGroup(groupElem);
109         }
110
111         // 必要に応じモーフ枠に不変空リスト登録
112         for(MorphType morphType : MorphType.values()){
113             if( ! TYPED_MAP.containsKey(morphType) ){
114                 TYPED_MAP.put(morphType, EMPTY);
115             }
116         }
117
118         return;
119     }
120
121     /**
122      * モーフグループ構造を解読する。
123      * @param groupElem morphGroup要素
124      */
125     private static void parseGroup(Element groupElem){
126         String typeAttr = groupElem.getAttribute(ATTR_TYPE);
127         MorphType morphType = MorphType.valueOf(typeAttr);
128
129         NodeList morphList = groupElem.getElementsByTagName(ELEM_MORPH);
130         int morphNo = morphList.getLength();
131         List<TypicalMorph> groupedList =
132                 new ArrayList<TypicalMorph>(morphNo);
133
134         for(int idx = 0; idx < morphNo; idx++){
135             Element morphElem = (Element) morphList.item(idx);
136             TypicalMorph morph = parseMorph(morphElem, morphType);
137             groupedList.add(morph);
138             MORPH_ALIAS_MAP.addAlias(morph);
139         }
140
141         groupedList = Collections.unmodifiableList(groupedList);
142         TYPED_MAP.put(morphType, groupedList);
143
144         return;
145     }
146
147     /**
148      * morph要素を解読する。
149      * @param morphElem morph要素
150      * @param mtype モーフ種別
151      * @return モーフ情報
152      */
153     private static TypicalMorph parseMorph(Element morphElem,
154                                              MorphType mtype ){
155         NodeList primaryNodes = morphElem.getElementsByTagName(ELEM_PRIMARY);
156         NodeList globalNodes  = morphElem.getElementsByTagName(ELEM_GLOBAL);
157         int primaryNo = primaryNodes.getLength();
158         int globalNo  = globalNodes.getLength();
159
160         assert primaryNo > 0;
161
162         TypicalMorph morph = new TypicalMorph(mtype, primaryNo, globalNo);
163
164         for(int idx = 0; idx < primaryNo; idx++){
165             Element primaryElem = (Element) primaryNodes.item(idx);
166             String primaryName = primaryElem.getAttribute(ATTR_NAME);
167             morph.addPrimaryName(primaryName);
168         }
169
170         for(int idx = 0; idx < globalNo; idx++){
171             Element globalElem = (Element) globalNodes.item(idx);
172             String globalName = globalElem.getAttribute(ATTR_NAME);
173             morph.addGlobalName(globalName);
174         }
175
176         return morph;
177     }
178
179     /**
180      * 全モーフ情報に通し番号を付ける。
181      *
182      * <p>同一グループ内ではXMLでの定義順が反映される。
183      */
184     private static void numbering(){
185         int order = 0;
186         for(MorphType morphType : MorphType.values()){
187             for(TypicalMorph morph : TYPED_MAP.get(morphType)){
188                 morph.setOrderNo(order++);
189             }
190         }
191
192         return;
193     }
194
195     /**
196      * 種別ごとのモーフ情報不変リストを取得する。
197      * @param morphType モーフ種別
198      * @return モーフ情報不変リスト
199      */
200     public static List<TypicalMorph> getTypicalMorphList(
201             MorphType morphType ){
202         List<TypicalMorph> result = TYPED_MAP.get(morphType);
203         return result;
204     }
205
206     /**
207      * プライマリ名の合致するモーフ情報を返す。
208      * NFKCで正規化されたプライマリ名で検索される。
209      * @param primaryName プライマリ名
210      * @return モーフ情報。見つからなければnull
211      */
212     public static TypicalMorph findWithPrimary(String primaryName){
213         TypicalMorph result = MORPH_ALIAS_MAP.getAliasByPrimary(primaryName);
214         return result;
215     }
216
217     /**
218      * グローバル名の合致するモーフ情報を返す。
219      * NFKCで正規化されたグローバル名で検索される。
220      * @param globalName グローバル名
221      * @return モーフ情報。見つからなければnull
222      */
223     public static TypicalMorph findWithGlobal(String globalName){
224         TypicalMorph result = MORPH_ALIAS_MAP.getAliasByGlobal(globalName);
225         return result;
226     }
227
228     /**
229      * プライマリ名をグローバル名に変換する。
230      * @param primaryName プライマリ名
231      * @return グローバル名。見つからなければnull
232      */
233     public static String primary2global(String primaryName){
234         String globalName = MORPH_ALIAS_MAP.primary2global(primaryName);
235         return globalName;
236     }
237
238     /**
239      * グローバル名をプライマリ名へ変換する。
240      * @param globalName グローバル名
241      * @return プライマリ名。見つからなければnull
242      */
243     public static String global2primary(String globalName){
244         String primaryName = MORPH_ALIAS_MAP.global2primary(globalName);
245         return primaryName;
246     }
247
248
249     /**
250      * モーフ種別を返す。
251      * @return モーフ種別
252      */
253     public MorphType getMorphType(){
254         return this.type;
255     }
256
257 }