OSDN Git Service

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