]> gitweb.fperrin.net Git - DictionaryPC.git/blob - src/com/hughes/android/dictionary/parser/EnWiktionaryXmlParser.java
go
[DictionaryPC.git] / src / com / hughes / android / dictionary / parser / EnWiktionaryXmlParser.java
1 package com.hughes.android.dictionary.parser;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.util.ArrayList;
6 import java.util.List;
7 import java.util.regex.Pattern;
8
9 import javax.xml.parsers.ParserConfigurationException;
10 import javax.xml.parsers.SAXParser;
11 import javax.xml.parsers.SAXParserFactory;
12
13 import org.xml.sax.Attributes;
14 import org.xml.sax.SAXException;
15
16 import com.hughes.android.dictionary.engine.DictionaryBuilder;
17 import com.hughes.android.dictionary.engine.IndexBuilder;
18
19 public class EnWiktionaryXmlParser extends org.xml.sax.helpers.DefaultHandler implements WikiCallback {
20
21   final DictionaryBuilder dict;
22   
23   final IndexBuilder[] indexBuilders;
24   final Pattern[] langPatterns;
25
26   StringBuilder titleBuilder;
27   StringBuilder textBuilder;
28   StringBuilder currentBuilder = null;
29
30   public EnWiktionaryXmlParser(final DictionaryBuilder builder, final Pattern[] langPatterns, final int enIndexBuilder) {
31     assert langPatterns.length == 2;
32     this.dict = builder;
33     this.indexBuilders = dict.indexBuilders.toArray(new IndexBuilder[0]);
34     this.langPatterns = langPatterns;
35   }
36
37   @Override
38   public void startElement(String uri, String localName, String qName,
39       Attributes attributes) {
40     currentBuilder = null;
41     if ("page".equals(qName)) {
42       titleBuilder = new StringBuilder();
43       
44       // Start with "\n" to better match certain strings.
45       textBuilder = new StringBuilder("\n");
46     } else if ("title".equals(qName)) {
47       currentBuilder = titleBuilder;
48     } else if ("text".equals(qName)) {
49       currentBuilder = textBuilder;
50     }
51   }
52
53   @Override
54   public void characters(char[] ch, int start, int length) throws SAXException {
55     if (currentBuilder != null) {
56       currentBuilder.append(ch, start, length);
57     }
58   }
59
60   @Override
61   public void endElement(String uri, String localName, String qName)
62       throws SAXException {
63     currentBuilder = null;
64     if ("page".equals(qName)) {
65       endPage();
66     }
67   }
68   
69
70   public void parse(final File file) throws ParserConfigurationException,
71       SAXException, IOException {
72     final SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
73     parser.parse(file, this);
74   }
75   
76   private void endPage() {
77     title = titleBuilder.toString();
78     currentDepth = 0;
79     words.clear();
80     WikiParser.parse(textBuilder.toString(), this);
81   }
82   
83   /**
84    * Two things can happen:
85    * 
86    * We can be in a ==German== section.  There we will see English definitions.
87    * Each POS should get its own QuickDic entry.  Pretty much everything goes
88    * in.
89    * 
90    * Or we can be in an ==English== section with English definitions
91    * and maybe see translations for languages we care about.
92    * 
93    * In either case, we need to differentiate the subsections (Noun, Verb, etc.)
94    * into separate QuickDic entries, but that's tricky--how do we know when we
95    * found a subsection?  Just ignore anything containing pronunciation and
96    * etymology?
97    * 
98    * How do we decide when to seal the deal on an entry?
99    * 
100    * Would be nice if the parser told us about leaving sections....
101    * 
102    * 
103    */
104
105   String title;
106   int currentDepth;
107   final List<WikiWord> words = new ArrayList<WikiWord>();
108   WikiWord currentWord;
109   WikiWord.PartOfSpeech currentPartOfSpeech;
110   WikiWord.TranslationSection currentTranslationSection;
111   
112   StringBuilder wikiBuilder = null;
113   
114   // ------------------------------------------------------------------------
115
116   @Override
117   public void onWikiLink(String[] args) {
118     if (wikiBuilder != null) {
119       wikiBuilder.append(args[args.length - 1]);
120     }
121   }
122
123   @Override
124   public void onTemplate(String[][] args) {
125     final String name = args[0][1];
126     if (name == "") {
127       
128     } else {
129       //System.out.println("Unhandled template: " + name);
130     }
131   }
132
133   @Override
134   public void onText(String text) {
135     if (wikiBuilder != null) {
136       wikiBuilder.append(text);
137       return;
138     }
139   }
140
141   @Override
142   public void onHeadingStart(int depth) {
143     wikiBuilder = new StringBuilder();
144     currentDepth = depth;
145     if (currentPartOfSpeech != null && depth <= currentPartOfSpeech.depth) {
146       currentPartOfSpeech = null;
147     }
148     if (currentWord != null && depth <= currentWord.depth) {
149       currentWord = null;
150     }
151   }
152   
153   final Pattern partOfSpeechHeader = Pattern.compile(
154       "Noun|Verb|Adjective|Adverb|Pronoun|Conjunction|Interjection|" +
155       "Preposition|Proper noun|Article|Prepositional phrase|Acronym|" +
156       "Abbreviation|Initialism|Contraction|Prefix|Suffix|Symbol|Letter|" +
157       "Ligature|Idiom|Phrase|" +
158       // These are @deprecated:
159       "Noun form|Verb form|Adjective form|Nominal phrase|Noun phrase|" +
160       "Verb phrase|Transitive verb|Intransitive verb|Reflexive verb");
161
162   @Override
163   public void onHeadingEnd(int depth) {
164     final String name = wikiBuilder.toString().trim();
165     wikiBuilder = null;
166     
167     final boolean lang1 = langPatterns[0].matcher(name).matches();
168     final boolean lang2 = langPatterns[1].matcher(name).matches();
169     if (name.equalsIgnoreCase("English") || lang1 || lang2) {
170       currentWord = new WikiWord(depth);
171       currentWord.language = name;
172       currentWord.isLang1 = lang1;
173       currentWord.isLang2 = lang2;
174       words.add(currentWord);
175       return;
176     }
177     
178     if (currentWord == null) {
179       return;
180     }
181     
182     if (partOfSpeechHeader.matcher(name).matches()) {
183       currentPartOfSpeech = new WikiWord.PartOfSpeech(depth);
184       currentWord.partsOfSpeech.add(currentPartOfSpeech);
185       return;
186     }
187     
188     if (name.equals("Translations")) {
189       if (currentWord == null || 
190           !currentWord.language.equals("English") || 
191           currentPartOfSpeech == null) {
192         System.out.println("Unexpected Translations section: " + title);
193         return;
194       }
195       currentTranslationSection = new WikiWord.TranslationSection();
196       currentPartOfSpeech.translationSections.add(currentTranslationSection);
197     } else {
198       currentTranslationSection = null;
199     }
200   }
201
202   @Override
203   public void onListItemStart(String header, int[] section) {
204     wikiBuilder = new StringBuilder();
205   }
206   
207
208   @Override
209   public void onListItemEnd(String header, int[] section) {
210     final String item = wikiBuilder.toString();
211     wikiBuilder = null;
212     
213     if (currentTranslationSection != null) {
214       final int colonPos = item.indexOf(':');
215       if (colonPos == -1) {
216         System.out.println("Invalid translation: " + item);
217         return;
218       }
219       final String lang = item.substring(0, colonPos);
220       final String trans = item.substring(colonPos + 1);
221       for (int i = 0; i < 2; ++i) {
222         if (langPatterns[i].matcher(lang).find()) {
223           currentTranslationSection.translations.get(i).add(trans);
224         }
225       }
226     }
227   }
228
229   @Override
230   public void onNewLine() {
231   }
232
233   @Override
234   public void onNewParagraph() {
235   }
236
237   // ----------------------------------------------------------------------
238   
239   public void onTransTrop(final String[][] args) {
240     currentTranslationSection = new WikiWord.TranslationSection();
241     currentPartOfSpeech.translationSections.add(currentTranslationSection);
242     
243     if (args.length > 1) {
244       currentTranslationSection.sense = args[1][1];
245     }
246   }
247
248   
249   // ----------------------------------------------------------------------
250
251   @Override
252   public void onComment(String text) {
253   }
254
255   @Override
256   public void onFormatBold(boolean boldOn) {
257   }
258
259   @Override
260   public void onFormatItalic(boolean italicOn) {
261   }
262
263   @Override
264   public void onUnterminated(String start, String rest) {
265     throw new RuntimeException(rest);
266   }
267   @Override
268   public void onInvalidHeaderEnd(String rest) {
269     throw new RuntimeException(rest);
270   }
271
272 }