001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: * Free SoftwareFoundation, Inc.
023: * 59 Temple Place, Suite 330
024: * Boston, MA 02111-1307 USA
025: *
026: * @author Scott Ferguson
027: */
028:
029: package com.caucho.relaxng;
030:
031: import com.caucho.config.ConfigException;
032: import com.caucho.relaxng.pattern.*;
033: import com.caucho.util.CharBuffer;
034: import com.caucho.util.L10N;
035: import com.caucho.xml.QName;
036:
037: import org.xml.sax.Attributes;
038: import org.xml.sax.SAXException;
039: import org.xml.sax.helpers.DefaultHandler;
040:
041: import java.util.ArrayList;
042: import java.util.HashMap;
043:
044: /**
045: * Builder for the relax.
046: */
047: public class RelaxBuilder extends DefaultHandler {
048: private static final String RELAX_S = "http://relaxng.org/ns/structure/1.0";
049:
050: private static final L10N L = new L10N(RelaxBuilder.class);
051:
052: private GrammarPattern _rootGrammar;
053: private GrammarPattern _grammar;
054:
055: private Pattern _pattern;
056: private String _ns = "";
057: private HashMap<String, String> _nsMap = new HashMap<String, String>();
058:
059: private CharBuffer _cb = new CharBuffer();
060:
061: private ArrayList<Pattern> _patternStack = new ArrayList<Pattern>();
062: private ArrayList<String> _nsStack = new ArrayList<String>();
063: private ArrayList<HashMap<String, String>> _nsMapStack = new ArrayList<HashMap<String, String>>();
064:
065: RelaxBuilder() {
066: }
067:
068: /**
069: * Gets the root pattern.
070: */
071: public GrammarPattern getGrammar() {
072: return _rootGrammar;
073: }
074:
075: public void startPrefixMapping(String prefix, String uri)
076: throws SAXException {
077: _nsMapStack.add(_nsMap);
078: _nsMap = new HashMap<String, String>(_nsMap);
079: _nsMap.put(prefix, uri);
080: }
081:
082: public void endPrefixMapping(String prefix) throws SAXException {
083: _nsMapStack.add(_nsMap);
084: _nsMap = _nsMapStack.remove(_nsMapStack.size() - 1);
085: }
086:
087: /**
088: * handles new element.
089: */
090: public void startElement(String uri, String localName,
091: String qName, Attributes attrs) throws SAXException {
092: _cb.clear();
093:
094: try {
095: if (RELAX_S.equals(uri)) {
096: _patternStack.add(_pattern);
097: _nsStack.add(_ns);
098:
099: String ns = attrs.getValue("ns");
100: if (ns != null)
101: _ns = ns;
102:
103: if (localName.equals("grammar")) {
104: _grammar = new GrammarPattern();
105:
106: if (_rootGrammar == null)
107: _rootGrammar = _grammar;
108:
109: _pattern = null;
110: } else if (localName.equals("start")) {
111: if (_pattern != null || _grammar == null)
112: throw new RelaxException(
113: "<start> must be a direct child of <grammar>.");
114:
115: _pattern = new GroupPattern();
116: _grammar.setStart(_pattern);
117: } else if (localName.equals("define")) {
118: if (_pattern != null || _grammar == null)
119: throw new RelaxException(
120: "<define> must be a direct child of <grammar>.");
121:
122: String name = attrs.getValue("name");
123: if (name == null || name.equals(""))
124: throw new RelaxException(
125: L
126: .l("<define> requires a `name' attribute."));
127:
128: _pattern = new GroupPattern();
129: _grammar.setDefinition(name, _pattern);
130: } else if (localName.equals("name")) {
131: if (_pattern == null)
132: throw new RelaxException(
133: "<name> must be child of <element> or <attribute>.");
134:
135: _pattern = null;
136: } else if (localName.equals("nsName")) {
137: if (_pattern == null)
138: throw new RelaxException(
139: "<nsName> must be child of <element> or <attribute>.");
140:
141: _pattern = new NsNamePattern();
142: } else if (localName.equals("anyName")) {
143: if (_pattern == null)
144: throw new RelaxException(
145: "<anyName> must be child of <element> or <attribute>.");
146:
147: _pattern = new AnyNamePattern();
148: } else if (localName.equals("except")) {
149: if (_pattern == null)
150: throw new RelaxException(
151: "<except> must be child of <nsName> or <anyName>.");
152:
153: _pattern = new ExcludeNamePattern();
154: } else {
155: if (_grammar == null) {
156: _grammar = new GrammarPattern();
157: _rootGrammar = _grammar;
158: _pattern = new GroupPattern();
159: _grammar.setStart(_pattern);
160:
161: _patternStack.set(_patternStack.size() - 1,
162: _pattern);
163: }
164:
165: Pattern child = null;
166:
167: if (localName.equals("element")) {
168: String name = attrs.getValue("name");
169:
170: String defName = _grammar.generateId();
171:
172: child = new ElementPattern(defName);
173:
174: if (name != null) {
175: QName eltQName = getName(name);
176: child
177: .addNameChild(new NamePattern(
178: eltQName));
179: }
180:
181: if (name != null) {
182: QName attrQName = getName(name);
183: child.addNameChild(new NamePattern(
184: attrQName));
185: }
186:
187: _grammar.setDefinition(defName, child);
188: } else if (localName.equals("attribute")) {
189: String name = attrs.getValue("name");
190:
191: child = new AttributePattern();
192:
193: if (name != null) {
194: QName attrQName = new QName(name, _ns);
195: child.addNameChild(new NamePattern(
196: attrQName));
197: }
198: } else if (localName.equals("empty")) {
199: child = new EmptyPattern();
200: } else if (localName.equals("text")) {
201: child = new TextPattern();
202: } else if (localName.equals("data")) {
203: String type = attrs.getValue("type");
204:
205: if (type == null)
206: throw new RelaxException(
207: L
208: .l("<data> requires a `type' attribute."));
209:
210: child = new DataPattern(type);
211: } else if (localName.equals("value")) {
212: child = new DataPattern("string");
213: } else if (localName.equals("choice")) {
214: if (_pattern instanceof ElementPattern) {
215: ElementPattern eltPattern = (ElementPattern) _pattern;
216:
217: if (eltPattern.getNameChild() == null) {
218: child = new ChoiceNamePattern();
219: eltPattern
220: .addNameChild((NameClassPattern) child);
221: _pattern = child;
222: return;
223: }
224: }
225:
226: if (_pattern instanceof AttributePattern) {
227: AttributePattern attrPattern = (AttributePattern) _pattern;
228:
229: if (attrPattern.getNameChild() == null) {
230: child = new ChoiceNamePattern();
231: attrPattern
232: .addNameChild((NameClassPattern) child);
233: _pattern = child;
234: return;
235: }
236: }
237:
238: child = new ChoicePattern();
239: } else if (localName.equals("group")) {
240: child = new GroupPattern();
241: } else if (localName.equals("interleave")) {
242: child = new InterleavePattern();
243: } else if (localName.equals("zeroOrMore")) {
244: child = new ZeroOrMorePattern();
245: } else if (localName.equals("oneOrMore")) {
246: child = new ZeroOrMorePattern();
247: } else if (localName.equals("optional")) {
248: Pattern choice = new ChoicePattern();
249: choice.addChild(new EmptyPattern());
250: choice.setParent(_pattern);
251:
252: Pattern group = new GroupPattern();
253: group.setParent(choice);
254: choice.addChild(group);
255: _pattern = group;
256: return;
257: } else if (localName.equals("ref")) {
258: String name = attrs.getValue("name");
259: if (name == null || name.equals(""))
260: throw new RelaxException(
261: L
262: .l("<define> requires a `name' attribute."));
263: child = new RefPattern(_grammar, name);
264: } else
265: throw new ConfigException(L.l(
266: "<{0}> is an unknown relax element.",
267: localName));
268:
269: child.setParent(_pattern);
270: if (child.getElementName() == null)
271: child.setElementName(_pattern.getElementName());
272:
273: _pattern = child;
274: }
275: }
276: } catch (Exception e) {
277: throw new SAXException(getLocation() + e.getMessage(), e);
278: }
279: }
280:
281: public void characters(char ch[], int start, int length)
282: throws SAXException {
283: _cb.append(ch, start, length);
284: }
285:
286: /**
287: * handles the end of an element.
288: */
289: public void endElement(String uri, String localName, String qName)
290: throws SAXException {
291: try {
292: if (RELAX_S.equals(uri)) {
293: NameClassPattern nameChild = null;
294: Pattern child = _pattern;
295: String ns = _ns;
296:
297: _pattern = _patternStack
298: .remove(_patternStack.size() - 1);
299: _ns = _nsStack.remove(_nsStack.size() - 1);
300:
301: if (localName.equals("name")) {
302: nameChild = new NamePattern(getName(_cb.toString()));
303:
304: if (_pattern != null)
305: _pattern.addNameChild(nameChild);
306: } else if (localName.equals("nsName")) {
307: NsNamePattern nsName = (NsNamePattern) child;
308:
309: nsName.setNamespace(ns);
310:
311: if (_pattern != null)
312: _pattern.addNameChild(nsName);
313: } else if (localName.equals("anyName")) {
314: nameChild = (AnyNamePattern) child;
315:
316: if (_pattern != null)
317: _pattern.addNameChild(nameChild);
318: } else if (localName.equals("except")) {
319: ExcludeNamePattern exclude = (ExcludeNamePattern) child;
320:
321: if (_pattern instanceof NsNamePattern) {
322: NsNamePattern nsPattern = (NsNamePattern) _pattern;
323:
324: nsPattern.setExcept(exclude.getNameChild());
325: }
326:
327: if (_pattern instanceof AnyNamePattern) {
328: AnyNamePattern anyNamePattern = (AnyNamePattern) _pattern;
329:
330: anyNamePattern
331: .setExcept(exclude.getNameChild());
332: }
333: } else if (localName.equals("optional")) {
334: if (_pattern != null)
335: _pattern.addChild(child.getParent());
336: } else if (localName.equals("oneOrMore")) {
337: ZeroOrMorePattern starPattern = (ZeroOrMorePattern) child;
338: Pattern subPattern = starPattern.getPatterns();
339: Pattern group = new GroupPattern();
340: group.addChild(subPattern);
341: group.addChild(starPattern);
342:
343: if (_pattern != null)
344: _pattern.addChild(group);
345: } else if (child instanceof NameClassPattern) {
346: } else {
347: if (child != null)
348: child.endElement();
349:
350: if (_pattern != null)
351: _pattern.addChild(child);
352: }
353: }
354: } catch (Exception e) {
355: throw new SAXException(getLocation() + e.getMessage(), e);
356: }
357: }
358:
359: private QName getName(String name) {
360: int p = name.lastIndexOf(':');
361:
362: if (p > 0) {
363: String prefix = name.substring(0, p);
364: String ns = _nsMap.get(prefix);
365:
366: if (ns != null)
367: return new QName(name, ns);
368: else
369: return new QName(name, _ns);
370: } else
371: return new QName(name, _ns);
372: }
373:
374: /**
375: * Returns the location.
376: */
377: public String getLocation() {
378: return "";
379: }
380: }
|