001    /* PAVLOV -- Multiple Choice Study System
002     * Copyright (C) 2000 - 2004 T.J. Willis
003     * 
004     * This program is free software; you can redistribute it and/or
005     * modify it under the terms of the GNU General Public License
006     * as published by the Free Software Foundation; either version 2
007     * of the License, or (at your option) any later version.
008     *      
009     * This program is distributed in the hope that it will be useful,
010     * but WITHOUT ANY WARRANTY; without even the implied warranty of
011     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012     * GNU General Public License for more details.
013     *          
014     * You should have received a copy of the GNU General Public License
015     * along with this program; if not, write to the Free Software
016     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
017     *  
018     * $Header: /cvsroot/pavlov/net/sourceforge/pavlov/library/BookXMLHandler.java,v 1.6 2004/07/01 05:50:20 tj_willis Exp $
019     */ 
020    package net.sourceforge.pavlov.library;
021    
022    import org.xml.sax.*;
023    import org.xml.sax.helpers.*;
024    import java.io.*;
025    import java.nio.*;
026    import java.nio.charset.*;
027    import org.apache.log4j.*;
028    
029    
030    
031    /**
032     * Implementation of Sax's DefaultHandler for Book XML files
033     * @author <a href="mailto:tj_willis@users.sourceforge.net"></a>
034     * @version 1.0
035     * @see org.xml.sax.ContentHandler
036     * @see org.xml.sax.DefaultHandler
037     */
038    public final class BookXMLHandler extends DefaultHandler {
039       private  Book bk;
040        private Chapter cp;
041       private  Question q;
042        private CharArrayWriter contents = new CharArrayWriter();
043        private StringWriter buf = new StringWriter();
044        private int MODE_NONE = 0;
045       private  int MODE_CONTENTS = 1;
046       private  int MODE_TOPICS = 2;
047       private  int MODE_TEXT = 3;
048        private int MODE_RIGHTANSWER = 4;
049        private int MODE_WRONGANSWER = 5;
050        private int MODE_HINT = 6;
051        private int MODE_WRONGANSWERS = 7;
052       private  int mode = MODE_NONE;
053        private Category cat 
054            = Category.getInstance(BookXMLHandler.class.getName());
055        //private Charset utf8;
056    
057        // Override methods of the DefaultHandler class
058        // to gain notification of SAX Events.
059        //
060        // See org.xml.sax.ContentHandler for all available events.
061        //
062        /**
063         * Called when sax starts reading the file.
064         *
065         * @exception SAXException if an error occurs
066         */
067        public void startDocument() throws SAXException {
068            cat.setLevel(Level.WARN);
069            bk = new Book();
070            /*
071            try {
072                utf8 = Charset.forName("UTF-8");
073            } catch (Exception e) {
074                cat.warn("Can't get UTF-8 encoder",e);
075                utf8 = Charset.defaultCharset();
076                }*/
077        }
078            
079        /**
080         * Called when sax ends reading the file.
081         *
082         * @exception SAXException if an error occurs
083         */
084        public void endDocument() throws SAXException {
085    
086        }
087    
088        /**
089         * Called when a start tag is found.
090         *
091         * @param namespaceURI a <code>String</code> value
092         * @param localName a <code>String</code> value
093         * @param qName a <code>String</code> value
094         * @param attr an <code>Attributes</code> value
095         * @exception SAXException if an error occurs
096         */
097        public void startElement(String namespaceURI,
098            String localName,
099            String qName,
100            Attributes attr) throws SAXException {
101    
102            contents.reset();
103            buf = new StringWriter(); //.delete(0,-1);
104    
105            if (localName.equals("BOOK")) {
106                String key, value;
107    
108                for (int i = 0; i < attr.getLength(); i++) {
109                    key = attr.getLocalName(i);
110                    value = attr.getValue(i);
111                    if (key.equals("NAME")) bk.setName(value);
112                    else if (key.equals("AUTHOR")) bk.setAuthor(value);
113                    else if (key.equals("COVER")) bk.setCover(value);
114                }
115            } else if (localName.equals("CHAPTER")) {
116                cp = new Chapter();
117                String key, value;
118    
119                for (int i = 0; i < attr.getLength(); i++) {
120                    key = attr.getLocalName(i);
121                    value = attr.getValue(i);
122                    if (key.equals("NAME")) cp.setName(value);
123                    else if (key.equals("AUTHOR")) cp.setAuthor(value);
124                    else if (key.equals("COVER")) cp.setCover(value);
125                }
126            } else if (localName.equals("QUESTION")) {
127                q = new Question();
128                String key, value;
129    
130                for (int i = 0; i < attr.getLength(); i++) {
131                    key = attr.getLocalName(i);
132                    value = attr.getValue(i);
133                    if (key.equals("ID")) q.setId(value);
134                    if (key.equals("IMG")) q.setImageFile(value);
135                    if (key.equals("SOUND")) q.setSoundFile(value);
136                    //else if (key.equals("DATE")) qd.setLast(value);
137                }
138                        
139            } else if (localName.equals("WRONGANSWER")) {
140                mode = MODE_WRONGANSWER;                
141            } else if (localName.equals("WRONGANSWERS")) {
142                mode = MODE_WRONGANSWERS;               
143            } else if (localName.equals("RIGHTANSWER")) {
144                mode = MODE_RIGHTANSWER;
145        
146            } else if (localName.equals("CONTENTS")) {
147                mode = MODE_CONTENTS;
148        
149            } else if (localName.equals("TOPICS")) {
150                mode = MODE_TOPICS;
151        
152            } else if (localName.equals("TEXT")) {
153                mode = MODE_TEXT;
154        
155            } else if (localName.equals("HINT")) {
156                mode = MODE_HINT;
157            }else {
158                cat.warn("Unrecognized book XML element [ " +
159                    localName + " ]");              
160    
161                // Also, let's print the attributes if 
162                // there are any...
163                for (int i = 0; i < attr.getLength(); i++) {
164                    cat.warn("   ATTRIBUTE: " +
165                        attr.getLocalName(i) +
166                        " VALUE: " + 
167                        attr.getValue(i));
168                }
169                        
170            } 
171        }
172            
173        /**
174         * Called when an END tag is found.
175         *
176         * @param namespaceURI a <code>String</code> value
177         * @param localName a <code>String</code> value
178         * @param qName a <code>String</code> value
179         * @exception SAXException if an error occurs
180         */
181        public void endElement(String namespaceURI,
182            String localName,
183            String qName) throws SAXException {
184    
185            // n.b.: don't zero-out mode for "HINT" or "WRONGANSWER"
186            if (localName.equals("BOOK")) {
187              // do nothing
188            } else if (localName.equals("CHAPTER")) {
189                bk.addChapter(cp);
190            } else if (localName.equals("QUESTION")) {
191                cp.addQuestion(q);
192            } else if (localName.equals("HINT")) {
193                q.addHint(buf.toString());
194            } else if (localName.equals("WRONGANSWER")) {
195                q.addWrongAnswer(encode(buf.toString()));
196            } else if (localName.equals("WRONGANSWERS")) {//q.addWrongAnswer(buf.toString());
197            } else if (localName.equals("RIGHTANSWER")) {
198                q.setRightAnswer(encode(buf.toString()));
199            } else if (localName.equals("TOPICS")) {
200                cp.setDescription(buf.toString());
201            } else if (localName.equals("TEXT")) {
202                q.setText( encode(buf.toString()));
203            } else if (localName.equals("CONTENTS")) {
204                bk.setDescription(buf.toString());
205            } else {
206                cat.warn("Unrecognized Book End Element[ " +
207                    localName + " ]");
208            }
209        } 
210            
211        private String encode(String in){
212            if(in==null) return null;
213            return in;
214    //         ByteBuffer b = utf8.encode(in);
215    //         byte arr[] = b.array();
216    //         String s = in;
217    //         try {
218    //             s = new String(arr,"UTF-8");
219    //             //System.out.println("encoded " + s);
220    //         } catch(Exception e) { 
221    //             cat.warn("Exception encoding " +in,e);
222    //         }
223    //         return s;
224    
225        }
226    
227        /**
228         * Called when sax reads characters that are not start or end tags.
229         *
230         * @param ch a <code>char[]</code> value
231         * @param start an <code>int</code> value
232         * @param length an <code>int</code> value
233         * @exception SAXException if an error occurs
234         */
235        public void characters(char[] ch, int start, int length) 
236            throws SAXException {
237            //contents.write(ch, start, length);
238            buf.write(ch,start,length);
239        }
240    
241    
242        /**
243         * Returns the loaded book.
244         * @return a <code>Book</code> value
245         */
246        public Book getBook() {
247            return bk;
248        }
249    }
250