OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [gnu/] [xml/] [validation/] [relaxng/] [FullSyntaxBuilder.java] - Blame information for rev 769

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 769 jeremybenn
/* FullSyntaxBuilder.java --
2
   Copyright (C) 2006  Free Software Foundation, Inc.
3
 
4
This file is part of GNU Classpath.
5
 
6
GNU Classpath is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2, or (at your option)
9
any later version.
10
 
11
GNU Classpath is distributed in the hope that it will be useful, but
12
WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
General Public License for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with GNU Classpath; see the file COPYING.  If not, write to the
18
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
02110-1301 USA.
20
 
21
Linking this library statically or dynamically with other modules is
22
making a combined work based on this library.  Thus, the terms and
23
conditions of the GNU General Public License cover the whole
24
combination.
25
 
26
As a special exception, the copyright holders of this library give you
27
permission to link this library with independent modules to produce an
28
executable, regardless of the license terms of these independent
29
modules, and to copy and distribute the resulting executable under
30
terms of your choice, provided that you also meet, for each linked
31
independent module, the terms and conditions of the license of that
32
module.  An independent module is a module which is not derived from
33
or based on this library.  If you modify this library, you may extend
34
this exception to your version of the library, but you are not
35
obligated to do so.  If you do not wish to do so, delete this
36
exception statement from your version. */
37
 
38
package gnu.xml.validation.relaxng;
39
 
40
import java.io.InputStream;
41
import java.io.IOException;
42
import java.io.UnsupportedEncodingException;
43
import java.net.URL;
44
import java.net.URLEncoder;
45
import java.util.Collections;
46
import java.util.HashMap;
47
import java.util.HashSet;
48
import java.util.Iterator;
49
import java.util.LinkedList;
50
import java.util.List;
51
import java.util.Map;
52
import java.util.Set;
53
import javax.xml.XMLConstants;
54
import javax.xml.parsers.DocumentBuilder;
55
import javax.xml.parsers.DocumentBuilderFactory;
56
import javax.xml.parsers.ParserConfigurationException;
57
 
58
import org.relaxng.datatype.DatatypeException;
59
import org.relaxng.datatype.DatatypeLibrary;
60
import org.relaxng.datatype.helpers.DatatypeLibraryLoader;
61
import org.w3c.dom.Document;
62
import org.w3c.dom.Element;
63
import org.w3c.dom.NamedNodeMap;
64
import org.w3c.dom.Node;
65
import org.xml.sax.SAXException;
66
 
67
import gnu.xml.stream.XMLParser;
68
 
69
/**
70
 * Parses a RELAX NG XML DOM tree, constructing a compiled internal
71
 * representation.
72
 *
73
 * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
74
 */
75
class FullSyntaxBuilder
76
{
77
 
78
  /**
79
   * Complete vocabulary (elements and attributes) of the full syntax.
80
   */
81
  static final Map VOCABULARY = new HashMap();
82
  static final Set STRIPPED_ATTRIBUTES = new HashSet();
83
  static final Set PATTERN_ELEMENTS = new HashSet();
84
  static
85
  {
86
    Set elementAttrs = Collections.singleton("name");
87
    Set dataAttrs = new HashSet();
88
    dataAttrs.add("type");
89
    dataAttrs.add("datatypeLibrary");
90
    Set valueAttrs = new HashSet();
91
    valueAttrs.add("type");
92
    valueAttrs.add("datatypeLibrary");
93
    valueAttrs.add("ns");
94
    Set externalAttrs = Collections.singleton("href");
95
    Set startAttrs = Collections.singleton("combine");
96
    Set defineAttrs = new HashSet();
97
    defineAttrs.add("name");
98
    defineAttrs.add("combine");
99
    Set nsAttrs = Collections.singleton("ns");
100
 
101
    VOCABULARY.put("element", elementAttrs);
102
    VOCABULARY.put("attribute", elementAttrs);
103
    VOCABULARY.put("group", Collections.EMPTY_SET);
104
    VOCABULARY.put("interleave", Collections.EMPTY_SET);
105
    VOCABULARY.put("choice", Collections.EMPTY_SET);
106
    VOCABULARY.put("optional", Collections.EMPTY_SET);
107
    VOCABULARY.put("zeroOrMore", Collections.EMPTY_SET);
108
    VOCABULARY.put("oneOrMore", Collections.EMPTY_SET);
109
    VOCABULARY.put("list", Collections.EMPTY_SET);
110
    VOCABULARY.put("mixed", Collections.EMPTY_SET);
111
    VOCABULARY.put("ref", elementAttrs);
112
    VOCABULARY.put("parentRef", elementAttrs);
113
    VOCABULARY.put("empty", Collections.EMPTY_SET);
114
    VOCABULARY.put("text", Collections.EMPTY_SET);
115
    VOCABULARY.put("value", valueAttrs);
116
    VOCABULARY.put("data", dataAttrs);
117
    VOCABULARY.put("notAllowed", Collections.EMPTY_SET);
118
    VOCABULARY.put("externalRef", externalAttrs);
119
    VOCABULARY.put("grammar", Collections.EMPTY_SET);
120
    VOCABULARY.put("param", elementAttrs);
121
    VOCABULARY.put("except", Collections.EMPTY_SET);
122
    VOCABULARY.put("div", Collections.EMPTY_SET);
123
    VOCABULARY.put("include", externalAttrs);
124
    VOCABULARY.put("start", startAttrs);
125
    VOCABULARY.put("define", defineAttrs);
126
    VOCABULARY.put("name", nsAttrs);
127
    VOCABULARY.put("anyName", Collections.EMPTY_SET);
128
    VOCABULARY.put("nsName", nsAttrs);
129
 
130
    STRIPPED_ATTRIBUTES.add("name");
131
    STRIPPED_ATTRIBUTES.add("type");
132
    STRIPPED_ATTRIBUTES.add("combine");
133
 
134
    PATTERN_ELEMENTS.add("element");
135
    PATTERN_ELEMENTS.add("attribute");
136
    PATTERN_ELEMENTS.add("group");
137
    PATTERN_ELEMENTS.add("interleave");
138
    PATTERN_ELEMENTS.add("choice");
139
    PATTERN_ELEMENTS.add("optional");
140
    PATTERN_ELEMENTS.add("zeroOrMore");
141
    PATTERN_ELEMENTS.add("oneOrMore");
142
    PATTERN_ELEMENTS.add("list");
143
    PATTERN_ELEMENTS.add("mixed");
144
    PATTERN_ELEMENTS.add("ref");
145
    PATTERN_ELEMENTS.add("parentRef");
146
    PATTERN_ELEMENTS.add("empty");
147
    PATTERN_ELEMENTS.add("text");
148
    PATTERN_ELEMENTS.add("value");
149
    PATTERN_ELEMENTS.add("data");
150
    PATTERN_ELEMENTS.add("notAllowed");
151
    PATTERN_ELEMENTS.add("externalRef");
152
    PATTERN_ELEMENTS.add("grammar");
153
  }
154
 
155
  private Set urls; // recursion checking
156
  private int refCount; // creation of ref names
157
  private Map datatypeLibraries;
158
 
159
  /**
160
   * Parse the specified document into a grammar.
161
   */
162
  synchronized Grammar parse(Document doc)
163
    throws IOException
164
  {
165
    urls = new HashSet();
166
    refCount = 1;
167
 
168
    doc.normalizeDocument(); // Normalize XML document
169
    transform(doc); // Apply transformation rules to provide simple syntax
170
 
171
    // 4.18. grammar element
172
    Element p = doc.getDocumentElement();
173
    Element grammar =
174
      doc.createElementNS(XMLConstants.RELAXNG_NS_URI, "grammar");
175
    Element start =
176
      doc.createElementNS(XMLConstants.RELAXNG_NS_URI, "start");
177
    doc.removeChild(p);
178
    doc.appendChild(grammar);
179
    grammar.appendChild(start);
180
    start.appendChild(p);
181
    transformGrammar(grammar, p);
182
    Element define = getNextSiblingElement(start);
183
    while (define != null)
184
      {
185
        Element next = getNextSiblingElement(define);
186
        String name = define.getAttribute("new-name");
187
        if (name != null)
188
          {
189
            define.setAttribute("name", name);
190
            define.removeAttribute("new-name");
191
          }
192
        else
193
          grammar.removeChild(define); // unreferenced
194
        define = next;
195
      }
196
 
197
    // 4.19. define and ref elements
198
    Set allDefines = new HashSet(), reachableDefines = new HashSet();
199
    getDefines(allDefines, grammar, grammar, false);
200
    getDefines(reachableDefines, grammar, start, true);
201
    allDefines.removeAll(reachableDefines);
202
    for (Iterator i = allDefines.iterator(); i.hasNext(); )
203
      {
204
        // remove unreachable defines
205
        Element d = (Element) i.next();
206
        Node parent = d.getParentNode();
207
        parent.removeChild(d);
208
      }
209
    // replace all elements that are not children of defines by refs to new
210
    // defines
211
    Set elements = new HashSet();
212
    getElements(elements, grammar, grammar);
213
    for (Iterator i = elements.iterator(); i.hasNext(); )
214
      {
215
        Element element = (Element) i.next();
216
        Node parent = element.getParentNode();
217
        if (!reachableDefines.contains(parent))
218
          {
219
            define =
220
              doc.createElementNS(XMLConstants.RELAXNG_NS_URI, "define");
221
            Element ref =
222
              doc.createElementNS(XMLConstants.RELAXNG_NS_URI, "ref");
223
            String name = createRefName();
224
            define.setAttribute("name", name);
225
            ref.setAttribute("name", name);
226
            parent.insertBefore(ref, element);
227
            define.appendChild(element);
228
            grammar.appendChild(define);
229
            reachableDefines.add(define);
230
          }
231
      }
232
    // Get defines that don't have element children
233
    for (Iterator i = reachableDefines.iterator(); i.hasNext(); )
234
      {
235
        Element d = (Element) i.next();
236
        Element child = getFirstChildElement(d);
237
        if (child != null && "element".equals(child.getLocalName()))
238
          i.remove();
239
      }
240
    // Expand refs that refer to these defines
241
    expandRefs(reachableDefines, grammar);
242
    // Remove any defines that don't have element children
243
    for (Iterator i = reachableDefines.iterator(); i.hasNext(); )
244
      {
245
        Element d = (Element) i.next();
246
        Node parent = d.getParentNode();
247
        parent.removeChild(d);
248
      }
249
 
250
    transform2(p); // Apply second stage transformation rules
251
 
252
    Grammar ret = parseGrammar(grammar);
253
    datatypeLibraries = null; // free datatype libraries cache
254
    return ret;
255
  }
256
 
257
  private void getDefines(Set defines, Element grammar, Element node,
258
                          boolean followRefs)
259
  {
260
    String elementName = node.getLocalName();
261
    if ("define".equals(elementName))
262
      defines.add(node);
263
    else if ("ref".equals(elementName) && followRefs)
264
      {
265
        String rname = node.getAttribute("name");
266
        Element define = getFirstChildElement(grammar);
267
        define = getNextSiblingElement(define);
268
        while (define != null)
269
          {
270
            String dname = define.getAttribute("name");
271
            if (rname.equals(dname))
272
              {
273
                getDefines(defines, grammar, node, followRefs);
274
                break;
275
              }
276
            define = getNextSiblingElement(define);
277
          }
278
      }
279
    for (Element child = getFirstChildElement(node); child != null;
280
         child = getNextSiblingElement(child))
281
      getDefines(defines, grammar, child, followRefs);
282
  }
283
 
284
  private void getElements(Set elements, Element grammar, Element node)
285
  {
286
    String elementName = node.getLocalName();
287
    if ("element".equals(elementName))
288
      elements.add(node);
289
    for (Element child = getFirstChildElement(node); child != null;
290
         child = getNextSiblingElement(child))
291
      getElements(elements, grammar, child);
292
  }
293
 
294
  private void expandRefs(Set defines, Element node)
295
    throws GrammarException
296
  {
297
    String elementName = node.getLocalName();
298
    if ("ref".equals(elementName))
299
      {
300
        String rname = node.getAttribute("name");
301
        for (Iterator i = defines.iterator(); i.hasNext(); )
302
          {
303
            Element define = (Element) i.next();
304
            String dname = define.getAttribute("name");
305
            if (rname.equals(dname))
306
              {
307
                Element child = getFirstChildElement(define);
308
                forbidRefs(child, rname);
309
                Element refChild = (Element) child.cloneNode(true);
310
                Node parent = node.getParentNode();
311
                parent.insertBefore(refChild, node);
312
                parent.removeChild(node);
313
                node = refChild;
314
                break;
315
              }
316
          }
317
      }
318
    for (Element child = getFirstChildElement(node); child != null;
319
         child = getNextSiblingElement(child))
320
      expandRefs(defines, child);
321
  }
322
 
323
  private void forbidRefs(Element node, String name)
324
    throws GrammarException
325
  {
326
    String elementName = node.getLocalName();
327
    if ("ref".equals(elementName))
328
      {
329
        String rname = node.getAttribute("name");
330
        if (name.equals(rname))
331
          throw new GrammarException("cannot expand ref with name '" + name +
332
                                     "' due to circularity");
333
      }
334
    for (Element child = getFirstChildElement(node); child != null;
335
         child = getNextSiblingElement(child))
336
      forbidRefs(child, name);
337
  }
338
 
339
  private void transform(Node node)
340
    throws IOException
341
  {
342
    Node parent = node.getParentNode();
343
    switch (node.getNodeType())
344
      {
345
      case Node.ELEMENT_NODE:
346
        // 4.1 Annotations
347
        String elementNs = node.getNamespaceURI();
348
        String elementName = node.getLocalName();
349
        if (!XMLConstants.RELAXNG_NS_URI.equals(elementNs) ||
350
            !VOCABULARY.containsKey(elementName))
351
          parent.removeChild(node);
352
        else
353
          {
354
            Set allowedAttrs = (Set) VOCABULARY.get(elementName);
355
            NamedNodeMap attrs = node.getAttributes();
356
            int len = attrs.getLength();
357
            for (int i = len - 1; i >= 0; i--)
358
              {
359
                Node attr = attrs.item(i);
360
                String attrNs = attr.getNamespaceURI();
361
                String attrName = attr.getLocalName();
362
                if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(attrNs))
363
                  continue; // ignore namespace nodes
364
                if (!(XMLConstants.RELAXNG_NS_URI.equals(attrNs) ||
365
                      attrNs == null) ||
366
                    !allowedAttrs.contains(attrName))
367
                  attrs.removeNamedItemNS(attrNs, attrName);
368
                else
369
                  {
370
                    // 4.2 Whitespace
371
                    if (STRIPPED_ATTRIBUTES.contains(attrName))
372
                      attr.setNodeValue(attr.getNodeValue().trim());
373
                    // 4.3 datatypeLibrary attribute
374
                    else if ("datatypeLibrary".equals(attrName))
375
                      {
376
                        String dl = attr.getNodeValue();
377
                        attr.setNodeValue(escapeURL(dl));
378
                      }
379
                    // 4.5. href attribute
380
                    else if ("href".equals(attrName))
381
                      {
382
                        String href = attr.getNodeValue();
383
                        href = XMLParser.absolutize(node.getBaseURI(),
384
                                                    escapeURL(href));
385
                        attr.setNodeValue(href);
386
                      }
387
                  }
388
              }
389
            // 4.3 datatypeLibrary attribute
390
            if ("data".equals(elementName) || "value".equals(elementName))
391
              {
392
                Element element = (Element) node;
393
                String dl = element.getAttribute("datatypeLibrary");
394
                if (dl == null)
395
                  {
396
                    Node p = parent;
397
                    while (dl == null && p != null &&
398
                           p.getNodeType() == Node.ELEMENT_NODE)
399
                      {
400
                        dl = ((Element) p)
401
                          .getAttribute("datatypeLibrary");
402
                        p = p.getParentNode();
403
                      }
404
                    if (dl == null)
405
                      dl = "";
406
                    element.setAttribute("datatypeLibrary", dl);
407
                  }
408
                // 4.4. type attribute of value element
409
                if ("value".equals(elementName))
410
                  {
411
                    String type = element.getAttribute("type");
412
                    if (type == null)
413
                      {
414
                        element.setAttribute("type", "token");
415
                        element.setAttribute("datatypeLibrary", "");
416
                      }
417
                  }
418
                // 4.16. Constraints
419
                // TODO validate type
420
              }
421
            // 4.6. externalRef element
422
            else if ("externalRef".equals(elementName))
423
              {
424
                Element externalRef = (Element) node;
425
                String href = externalRef.getAttribute("href");
426
                // check for recursion
427
                if (urls.contains(href))
428
                  throw new GrammarException("recursive href");
429
                urls.add(href);
430
                Element element = resolve(href);
431
                String eNs = element.getNamespaceURI();
432
                String eName = element.getLocalName();
433
                if (!(XMLConstants.RELAXNG_NS_URI.equals(eNs) ||
434
                      eNs == null) ||
435
                    !PATTERN_ELEMENTS.contains(eName))
436
                  throw new GrammarException("externally referenced element " +
437
                                             "is not a pattern");
438
                transform(element);
439
                urls.remove(href);
440
                String ns = element.getAttribute("ns");
441
                if (ns != null)
442
                  element.setAttribute("ns",
443
                                       externalRef.getAttribute("ns"));
444
                element = (Element) externalRef.getOwnerDocument()
445
                  .importNode(element, true);
446
                parent.replaceChild(element, externalRef);
447
                return;
448
              }
449
            // 4.7 include element
450
            else if ("include".equals(elementName))
451
              {
452
                Element include = (Element) node;
453
                String href = include.getAttribute("href");
454
                // check for recursion
455
                if (urls.contains(href))
456
                  throw new GrammarException("recursive href");
457
                urls.add(href);
458
                Element element = resolve(href);
459
                String eNs = element.getNamespaceURI();
460
                String eName = element.getLocalName();
461
                if (!(XMLConstants.RELAXNG_NS_URI.equals(eNs) ||
462
                      eNs == null) ||
463
                    !"grammar".equals(eName))
464
                  throw new GrammarException("included element is not " +
465
                                             "a grammar");
466
 
467
                transform(element);
468
                urls.remove(href);
469
                // handle components
470
                List includeComponents = getComponents(include);
471
                List grammarComponents = getComponents(element);
472
                for (Iterator i = includeComponents.iterator(); i.hasNext(); )
473
                  {
474
                    Element comp = (Element) i.next();
475
                    String compName = comp.getLocalName();
476
                    if ("start".equals(compName))
477
                      {
478
                        boolean found = false;
479
                        for (Iterator j = grammarComponents.iterator();
480
                             j.hasNext(); )
481
                          {
482
                            Element c2 = (Element) j.next();
483
                            if ("start".equals(c2.getLocalName()))
484
                              {
485
                                c2.getParentNode().removeChild(c2);
486
                                found = true;
487
                              }
488
                          }
489
                        if (!found)
490
                          throw new GrammarException("no start component in " +
491
                                                     "included grammar");
492
                      }
493
                    else if ("define".equals(compName))
494
                      {
495
                        String name = comp.getAttribute("name");
496
                        boolean found = false;
497
                        for (Iterator j = grammarComponents.iterator();
498
                             j.hasNext(); )
499
                          {
500
                            Element c2 = (Element) j.next();
501
                            if ("define".equals(c2.getLocalName()) &&
502
                                name.equals(c2.getAttribute("name")))
503
                              {
504
                                c2.getParentNode().removeChild(c2);
505
                                found = true;
506
                              }
507
                          }
508
                        if (!found)
509
                          throw new GrammarException("no define component " +
510
                                                     "with name '" + name +
511
                                                     "' in included grammar");
512
                      }
513
                  }
514
                // transform to div element
515
                Document doc = include.getOwnerDocument();
516
                Element includeDiv =
517
                  doc.createElementNS(XMLConstants.RELAXNG_NS_URI, "div");
518
                Element grammarDiv =
519
                  doc.createElementNS(XMLConstants.RELAXNG_NS_URI, "div");
520
                // XXX copy include non-href attributes (none defined?)
521
                element = (Element) doc.importNode(element, true);
522
                Node ctx = element.getFirstChild();
523
                while (ctx != null)
524
                  {
525
                    Node next = ctx.getNextSibling();
526
                    grammarDiv.appendChild(ctx);
527
                    ctx = next;
528
                  }
529
                includeDiv.appendChild(grammarDiv);
530
                ctx = include.getFirstChild();
531
                while (ctx != null)
532
                  {
533
                    Node next = ctx.getNextSibling();
534
                    includeDiv.appendChild(ctx);
535
                    ctx = next;
536
                  }
537
                parent.replaceChild(includeDiv, include);
538
                transform(includeDiv);
539
                return;
540
              }
541
            // 4.8. name attribute of element and attribute elements
542
            else if ("attribute".equals(elementName) ||
543
                     "element".equals(elementName))
544
              {
545
                Element element = (Element) node;
546
                String name = element.getAttribute("name");
547
                if (name != null)
548
                  {
549
                    Document doc = element.getOwnerDocument();
550
                    Element n =
551
                      doc.createElementNS(XMLConstants.RELAXNG_NS_URI, "name");
552
                    n.appendChild(doc.createTextNode(name));
553
                    Node first = element.getFirstChild();
554
                    if (first != null)
555
                      element.insertBefore(n, first);
556
                    else
557
                      element.appendChild(n);
558
                    if ("attribute".equals(elementName))
559
                      {
560
                        String ns = element.getAttribute("ns");
561
                        if (ns != null)
562
                          {
563
                            n.setAttribute("ns", ns);
564
                            element.removeAttribute("ns");
565
                          }
566
                      }
567
                    element.removeAttribute("name");
568
                  }
569
                // 4.12. Number of child elements
570
                if ("attribute".equals(elementName))
571
                  {
572
                    if (getComponents(node).size() == 1)
573
                      {
574
                        Document doc = node.getOwnerDocument();
575
                        Element text =
576
                          doc.createElementNS(XMLConstants.RELAXNG_NS_URI,
577
                                              "text");
578
                        node.appendChild(text);
579
                      }
580
                  }
581
                else // element
582
                  {
583
                    if (node.getChildNodes().getLength() > 2)
584
                      {
585
                        // transform to 2 child elements
586
                        Document doc = node.getOwnerDocument();
587
                        Element child =
588
                          doc.createElementNS(XMLConstants.RELAXNG_NS_URI,
589
                                              "group");
590
                        Node ctx = getFirstChildElement(node);
591
                        ctx = getNextSiblingElement(ctx); // skip 1
592
                        while (ctx != null)
593
                          {
594
                            Node next = getNextSiblingElement(ctx);
595
                            child.appendChild(ctx);
596
                            ctx = next;
597
                          }
598
                        node.appendChild(child);
599
                      }
600
                  }
601
              }
602
            // 4.11. div element
603
            else if ("div".equals(elementName))
604
              {
605
                Node ctx = node.getFirstChild();
606
                while (ctx != null)
607
                  {
608
                    Node next = ctx.getNextSibling();
609
                    parent.insertBefore(ctx, node);
610
                    transform(ctx);
611
                    ctx = next;
612
                  }
613
                parent.removeChild(node);
614
                return;
615
              }
616
            else if ("mixed".equals(elementName))
617
              {
618
                // 4.12. Number of child elements
619
                transformToOneChildElement(node, "group");
620
                // 4.13. mixed element
621
                Document doc = node.getOwnerDocument();
622
                Node interleave =
623
                  doc.createElementNS(XMLConstants.RELAXNG_NS_URI,
624
                                      "interleave");
625
                Node ctx = node.getFirstChild();
626
                while (ctx != null)
627
                  {
628
                    Node next = ctx.getNextSibling();
629
                    interleave.appendChild(ctx);
630
                    ctx = next;
631
                  }
632
                Node text =
633
                  doc.createElementNS(XMLConstants.RELAXNG_NS_URI,
634
                                      "text");
635
                interleave.appendChild(text);
636
                parent.insertBefore(interleave, node);
637
                parent.removeChild(node);
638
                node = interleave;
639
              }
640
            else if ("optional".equals(elementName))
641
              {
642
                // 4.12. Number of child elements
643
                transformToOneChildElement(node, "group");
644
                // 4.14. optional element
645
                Document doc = node.getOwnerDocument();
646
                Node choice =
647
                  doc.createElementNS(XMLConstants.RELAXNG_NS_URI,
648
                                      "choice");
649
                Node ctx = node.getFirstChild();
650
                while (ctx != null)
651
                  {
652
                    Node next = ctx.getNextSibling();
653
                    choice.appendChild(ctx);
654
                    ctx = next;
655
                  }
656
                Node empty =
657
                  doc.createElementNS(XMLConstants.RELAXNG_NS_URI,
658
                                      "empty");
659
                choice.appendChild(empty);
660
                parent.insertBefore(choice, node);
661
                parent.removeChild(node);
662
                node = choice;
663
              }
664
            else if ("zeroOrMore".equals(elementName))
665
              {
666
                // 4.12. Number of child elements
667
                transformToOneChildElement(node, "group");
668
                // 4.15. zeroOrMore element
669
                Document doc = node.getOwnerDocument();
670
                Node choice =
671
                  doc.createElementNS(XMLConstants.RELAXNG_NS_URI,
672
                                      "choice");
673
                Node oneOrMore =
674
                  doc.createElementNS(XMLConstants.RELAXNG_NS_URI,
675
                                      "oneOrMore");
676
                Node ctx = node.getFirstChild();
677
                while (ctx != null)
678
                  {
679
                    Node next = ctx.getNextSibling();
680
                    oneOrMore.appendChild(ctx);
681
                    ctx = next;
682
                  }
683
                Node empty =
684
                  doc.createElementNS(XMLConstants.RELAXNG_NS_URI,
685
                                      "empty");
686
                choice.appendChild(oneOrMore);
687
                choice.appendChild(empty);
688
                parent.insertBefore(choice, node);
689
                parent.removeChild(node);
690
                node = choice;
691
              }
692
            else if ("list".equals(elementName) ||
693
                     "oneOrMore".equals(elementName) ||
694
                     "define".equals(elementName))
695
              {
696
                // 4.12. Number of child elements
697
                transformToOneChildElement(node, "group");
698
              }
699
            else if ("except".equals(elementName))
700
              {
701
                // 4.12. Number of child elements
702
                transformToOneChildElement(node, "choice");
703
                // 4.16. Constraints
704
                String parentName = parent.getLocalName();
705
                if ("anyName".equals(parentName))
706
                  forbidDescendants(node, Collections.singleton("anyName"));
707
                else if ("nsName".equals(parentName))
708
                  {
709
                    Set names = new HashSet();
710
                    names.add("nsName");
711
                    names.add("anyName");
712
                    forbidDescendants(node, names);
713
                  }
714
              }
715
            else if ("choice".equals(elementName) ||
716
                     "group".equals(elementName) ||
717
                     "interleave".equals(elementName))
718
              {
719
                // 4.12. Number of child elements
720
                Node ctx = getFirstChildElement(node);
721
                Node next = getNextSiblingElement(ctx);
722
                if (next == null)
723
                  {
724
                    // replace
725
                    parent.insertBefore(ctx, node);
726
                    parent.removeChild(node);
727
                    transform(ctx);
728
                    return;
729
                  }
730
                else
731
                  {
732
                    // transform to 2 child elements
733
                    Node next2 = getNextSiblingElement(next);
734
                    if (next2 != null)
735
                      {
736
                        Document doc = node.getOwnerDocument();
737
                        Node child =
738
                          doc.createElementNS(XMLConstants.RELAXNG_NS_URI,
739
                                              elementName);
740
                        child.appendChild(ctx);
741
                        child.appendChild(next);
742
                        node.insertBefore(next2, child);
743
                        transform(node); // recurse
744
                      }
745
                  }
746
              }
747
            // 4.17. combine attribute
748
            else if ("grammar".equals(elementName))
749
              {
750
                String combine = null;
751
                List nodes = new LinkedList();
752
                Node ctx = node.getFirstChild();
753
                while (ctx != null)
754
                  {
755
                    Node next = ctx.getNextSibling();
756
                    if ("start".equals(ctx.getLocalName()))
757
                      {
758
                        String c = ((Element) ctx).getAttribute("combine");
759
                        if (combine != null && !combine.equals(c))
760
                          throw new GrammarException("multiple start elements "+
761
                                                     "but no combine attribute");
762
                        combine = c;
763
                        nodes.add(ctx);
764
                      }
765
                    ctx = next;
766
                  }
767
                if (!nodes.isEmpty())
768
                  combineNodes(node, combine, "start", nodes);
769
                // defines
770
                Map defines = new HashMap();
771
                Map defineCombines = new HashMap();
772
                ctx = node.getFirstChild();
773
                while (ctx != null)
774
                  {
775
                    Node next = ctx.getNextSibling();
776
                    if ("define".equals(ctx.getLocalName()))
777
                      {
778
                        String name = ((Element) ctx).getAttribute("name");
779
                        combine = (String) defineCombines.get(name);
780
                        String c = ((Element) ctx).getAttribute("combine");
781
                        if (combine != null && !combine.equals(c))
782
                          throw new GrammarException("multiple define " +
783
                                                     "elements with name '"+
784
                                                     name + "' but no " +
785
                                                     "combine attribute");
786
                        defineCombines.put(name, c);
787
                        nodes = (List) defines.get(name);
788
                        if (nodes == null)
789
                          {
790
                            nodes = new LinkedList();
791
                            defines.put(name, nodes);
792
                          }
793
                        nodes.add(ctx);
794
                      }
795
                    ctx = next;
796
                  }
797
                for (Iterator i = defines.keySet().iterator(); i.hasNext(); )
798
                  {
799
                    String name = (String) i.next();
800
                    combine = (String) defineCombines.get(name);
801
                    nodes = (List) defines.get(name);
802
                    if (!nodes.isEmpty())
803
                      combineNodes(node, combine, "define", nodes);
804
                  }
805
              }
806
            // 4.9. ns attribute
807
            if ("name".equals(elementName) ||
808
                "nsName".equals(elementName) ||
809
                "value".equals(elementName))
810
              {
811
                Element element = (Element) node;
812
                String ns = element.getAttribute("ns");
813
                if (ns == null)
814
                  {
815
                    Node ctx = parent;
816
                    while (ns == null && ctx != null &&
817
                           ctx.getNodeType() == Node.ELEMENT_NODE)
818
                      {
819
                        ns = ((Element) ctx).getAttribute("ns");
820
                        ctx = ctx.getParentNode();
821
                      }
822
                    element.setAttribute("ns", (ns == null) ? "" : ns);
823
                  }
824
                if ("name".equals(elementName))
825
                  {
826
                    // 4.10. QNames
827
                    String name = element.getTextContent();
828
                    int ci = name.indexOf(':');
829
                    if (ci != -1)
830
                      {
831
                        String prefix = name.substring(0, ci);
832
                        element.setTextContent(name.substring(ci + 1));
833
                        ns = element.lookupNamespaceURI(prefix);
834
                        element.setAttribute("ns", (ns == null) ? "" : ns);
835
                      }
836
                    // 4.16. Constraints
837
                    if (isDescendantOfFirstChildOfAttribute(element) &&
838
                        "".equals(element.getAttribute("ns")) &&
839
                        "xmlns".equals(element.getTextContent()))
840
                      throw new GrammarException("name cannot be xmlns");
841
                  }
842
                else if ("nsName".equals(elementName))
843
                  {
844
                    // 4.16. Constraints
845
                    if (isDescendantOfFirstChildOfAttribute(element) &&
846
                        "http://www.w3.org/2000/xmlns"
847
                        .equals(element.getAttribute("ns")))
848
                      throw new GrammarException("nsName cannot be XMLNS URI");
849
                  }
850
              }
851
          }
852
 
853
        break;
854
      case Node.TEXT_NODE:
855
      case Node.CDATA_SECTION_NODE:
856
        // 4.2 Whitespace
857
        String parentName = parent.getLocalName();
858
        if ("name".equals(parentName))
859
          node.setNodeValue(node.getNodeValue().trim());
860
        if (!"param".equals(parentName) &&
861
            !"value".equals(parentName) &&
862
            isWhitespace(node.getNodeValue()))
863
          parent.removeChild(node);
864
        break;
865
      case Node.DOCUMENT_NODE:
866
        break;
867
      default:
868
        parent.removeChild(node);
869
      }
870
    // Transform children
871
    Node ctx = node.getFirstChild();
872
    while (ctx != null)
873
      {
874
        Node next = ctx.getNextSibling();
875
        transform(ctx);
876
        ctx = next;
877
      }
878
  }
879
 
880
  /**
881
   * Transforms the schema to place all defines under the top-level grammar
882
   * element and replace all other grammar elements by their start child.
883
   */
884
  private void transformGrammar(Node grammar, Node node)
885
    throws GrammarException
886
  {
887
    if (node.getNodeType() == Node.ELEMENT_NODE)
888
      {
889
        String elementName = node.getLocalName();
890
        if ("grammar".equals(elementName))
891
          {
892
            handleRefs(grammar, node, node);
893
            Node start = null;
894
            Node ctx = node.getFirstChild();
895
            while (ctx != null)
896
              {
897
                Node next = ctx.getNextSibling();
898
                String childName = ctx.getLocalName();
899
                if ("define".equals(childName))
900
                  grammar.appendChild(ctx);
901
                else if ("start".equals(childName))
902
                  start = ctx;
903
                ctx = next;
904
              }
905
            if (start == null)
906
              throw new GrammarException("no start element for grammar");
907
            Node p = getFirstChildElement(start);
908
            Node parent = node.getParentNode();
909
            parent.insertBefore(p, node);
910
            parent.removeChild(node);
911
            node = p;
912
          }
913
        Node ctx = node.getFirstChild();
914
        while (ctx != null)
915
          {
916
            Node next = ctx.getNextSibling();
917
            transformGrammar(grammar, ctx);
918
            ctx = next;
919
          }
920
      }
921
  }
922
 
923
  /**
924
   * Checks that all references in the specified grammar match a define in
925
   * the grammar.
926
   */
927
  private void handleRefs(Node grammar1, Node grammar2, Node node)
928
    throws GrammarException
929
  {
930
    if (node.getNodeType() == Node.ELEMENT_NODE)
931
      {
932
        String elementName = node.getLocalName();
933
        if ("ref".equals(elementName) || "parentRef".equals(elementName))
934
          {
935
            Node grammar = grammar2;
936
            if ("parentRef".equals(elementName))
937
              grammar = grammar1;
938
 
939
            String name = ((Element) node).getAttribute("name");
940
            if (name != null)
941
              throw new GrammarException("no name attribute on " +
942
                                         elementName);
943
            Node define = null;
944
            for (Node ctx = grammar.getFirstChild();
945
                 define == null && ctx != null;
946
                 ctx = ctx.getNextSibling())
947
              {
948
                if ("define".equals(ctx.getLocalName()))
949
                  {
950
                    String dname = ((Element) ctx).getAttribute("name");
951
                    if (name.equals(dname))
952
                      define = ctx;
953
                  }
954
              }
955
            if (define == null)
956
              throw new GrammarException("no define for '" + name + "'");
957
            name = ((Element) define).getAttribute("new-name");
958
            if (name == null)
959
              {
960
                name = createRefName();
961
                ((Element) define).setAttribute("new-name", name);
962
              }
963
            if ("parentRef".equals(elementName))
964
              {
965
                Document doc = node.getOwnerDocument();
966
                Node ref = doc.createElementNS(XMLConstants.RELAXNG_NS_URI,
967
                                               "ref");
968
                Node ctx = node.getFirstChild();
969
                while (ctx != null)
970
                  {
971
                    Node next = ctx.getNextSibling();
972
                    ref.appendChild(ctx);
973
                    ctx = next;
974
                  }
975
                Node parent = node.getParentNode();
976
                parent.insertBefore(ref, node);
977
                parent.removeChild(node);
978
                node = ref;
979
              }
980
            ((Element) node).setAttribute("name", name);
981
          }
982
        else if ("grammar".equals(elementName))
983
          {
984
            grammar1 = grammar2;
985
            grammar2 = node;
986
          }
987
        Node ctx = node.getFirstChild();
988
        while (ctx != null)
989
          {
990
            Node next = ctx.getNextSibling();
991
            handleRefs(grammar1, grammar2, ctx);
992
            ctx = next;
993
          }
994
      }
995
  }
996
 
997
  private String createRefName()
998
  {
999
    return "ref" + Integer.toString(refCount++);
1000
  }
1001
 
1002
  private void transform2(Node node)
1003
    throws GrammarException
1004
  {
1005
    Node parent = node.getParentNode();
1006
    if (node.getNodeType() == Node.ELEMENT_NODE)
1007
      {
1008
        String elementName = node.getLocalName();
1009
        // 4.20. notAllowed element
1010
        if ("notAllowed".equals(elementName))
1011
          {
1012
            String parentName = parent.getLocalName();
1013
            if ("attribute".equals(parentName) ||
1014
                "list".equals(parentName) ||
1015
                "group".equals(parentName) ||
1016
                "interleave".equals(parentName) ||
1017
                "oneOrMore".equals(parentName))
1018
              {
1019
                Node pp = parent.getParentNode();
1020
                pp.insertBefore(node, parent);
1021
                pp.removeChild(parent);
1022
                transform2(node); // apply recursively
1023
                return;
1024
              }
1025
            else if ("choice".equals(parentName))
1026
              {
1027
                Node p1 = getFirstChildElement(parent);
1028
                Node p2 = getNextSiblingElement(p1);
1029
                if (p1 == null || p2 == null)
1030
                  throw new GrammarException("choice does not have two " +
1031
                                             "children");
1032
                String p1Name = p1.getLocalName();
1033
                String p2Name = p2.getLocalName();
1034
                Node pp = parent.getParentNode();
1035
                if ("notAllowed".equals(p1Name) &&
1036
                    "notAllowed".equals(p2Name))
1037
                  {
1038
                    pp.insertBefore(p1, parent);
1039
                    pp.removeChild(parent);
1040
                    transform2(p1); //apply recursively
1041
                    return;
1042
                  }
1043
                else if ("notAllowed".equals(p1Name))
1044
                  {
1045
                    pp.insertBefore(p2, parent);
1046
                    pp.removeChild(parent);
1047
                    transform2(p2);
1048
                    return;
1049
                  }
1050
                else
1051
                  {
1052
                    pp.insertBefore(p1, parent);
1053
                    pp.removeChild(parent);
1054
                    transform2(p1);
1055
                    return;
1056
                  }
1057
              }
1058
            else if ("except".equals(parentName))
1059
              {
1060
                Node pp = parent.getParentNode();
1061
                pp.removeChild(parent);
1062
                return;
1063
              }
1064
          }
1065
        // 4.21. empty element
1066
        else if ("empty".equals(elementName))
1067
          {
1068
            String parentName = parent.getLocalName();
1069
            if ("group".equals(parentName) ||
1070
                "interleave".equals(parentName))
1071
              {
1072
                Node p1 = getFirstChildElement(parent);
1073
                Node p2 = getNextSiblingElement(p1);
1074
                if (p1 == null || p2 == null)
1075
                  throw new GrammarException(parentName + " does not have " +
1076
                                             "two children");
1077
                String p1Name = p1.getLocalName();
1078
                String p2Name = p2.getLocalName();
1079
                Node pp = parent.getParentNode();
1080
                if ("empty".equals(p1Name) &&
1081
                    "empty".equals(p2Name))
1082
                  {
1083
                    pp.insertBefore(p1, parent);
1084
                    pp.removeChild(parent);
1085
                    transform2(p1);
1086
                    return;
1087
                  }
1088
                else if ("empty".equals(p1Name))
1089
                  {
1090
                    pp.insertBefore(p2, parent);
1091
                    pp.removeChild(parent);
1092
                    transform2(p2);
1093
                    return;
1094
                  }
1095
                else
1096
                  {
1097
                    pp.insertBefore(p1, parent);
1098
                    pp.removeChild(parent);
1099
                    transform2(p1);
1100
                    return;
1101
                  }
1102
              }
1103
            else if ("choice".equals(parentName))
1104
              {
1105
                Node p1 = getFirstChildElement(parent);
1106
                Node p2 = getNextSiblingElement(p1);
1107
                if (p1 == null || p2 == null)
1108
                  throw new GrammarException(parentName + " does not have " +
1109
                                             "two children");
1110
                String p1Name = p1.getLocalName();
1111
                String p2Name = p2.getLocalName();
1112
                Node pp = parent.getParentNode();
1113
                if ("empty".equals(p1Name) &&
1114
                    "empty".equals(p2Name))
1115
                  {
1116
                    pp.insertBefore(p1, parent);
1117
                    pp.removeChild(parent);
1118
                    transform2(p1);
1119
                    return;
1120
                  }
1121
              }
1122
            else if ("oneOrMore".equals(parentName))
1123
              {
1124
                Node pp = parent.getParentNode();
1125
                pp.insertBefore(node, parent);
1126
                pp.removeChild(parent);
1127
                transform2(node);
1128
                return;
1129
              }
1130
          }
1131
        Node ctx = node.getFirstChild();
1132
        while (ctx != null)
1133
          {
1134
            Node next = ctx.getNextSibling();
1135
            transform2(ctx);
1136
            ctx = next;
1137
          }
1138
      }
1139
  }
1140
 
1141
  private static boolean isWhitespace(String text)
1142
  {
1143
    int len = text.length();
1144
    for (int i = 0; i < len; i++)
1145
      {
1146
        char c = text.charAt(i);
1147
        if (c != ' ' && c != '\t' && c != '\n' && c != '\r')
1148
          return false;
1149
      }
1150
    return true;
1151
  }
1152
 
1153
  private static String escapeURL(String url)
1154
  {
1155
    try
1156
      {
1157
        return URLEncoder.encode(url, "UTF-8");
1158
      }
1159
    catch (UnsupportedEncodingException e)
1160
      {
1161
        RuntimeException e2 = new RuntimeException("UTF-8 is unsupported");
1162
        e2.initCause(e);
1163
        throw e2;
1164
      }
1165
  }
1166
 
1167
  /**
1168
   * Resolve a URL to an element, as described in section 4.5.
1169
   */
1170
  private static Element resolve(String url)
1171
    throws IOException
1172
  {
1173
    try
1174
      {
1175
        URL u = new URL(url);
1176
        InputStream in = u.openStream();
1177
        DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
1178
        f.setNamespaceAware(true);
1179
        f.setCoalescing(true);
1180
        f.setExpandEntityReferences(true);
1181
        f.setIgnoringComments(true);
1182
        f.setIgnoringElementContentWhitespace(true);
1183
        DocumentBuilder b = f.newDocumentBuilder();
1184
        Document doc = b.parse(in, url);
1185
        in.close();
1186
        String fragment = u.getRef();
1187
        if (fragment != null)
1188
          return doc.getElementById(fragment);
1189
        return doc.getDocumentElement();
1190
      }
1191
    catch (SAXException e)
1192
      {
1193
        IOException e2 = new IOException("error parsing included element");
1194
        e2.initCause(e);
1195
        throw e2;
1196
      }
1197
    catch (ParserConfigurationException e)
1198
      {
1199
        IOException e2 = new IOException("error parsing included element");
1200
        e2.initCause(e);
1201
        throw e2;
1202
      }
1203
  }
1204
 
1205
  /**
1206
   * Returns the "components" of an element, as described in section 4.7.
1207
   */
1208
  private List getComponents(Node node)
1209
  {
1210
    List ret = new LinkedList();
1211
    for (Node ctx = node.getFirstChild(); ctx != null;
1212
         ctx = ctx.getNextSibling())
1213
      {
1214
        if (ctx.getNodeType() != Node.ELEMENT_NODE)
1215
          continue;
1216
        String ns = ctx.getNamespaceURI();
1217
        if (ns != null && !ns.equals(XMLConstants.RELAXNG_NS_URI))
1218
          continue;
1219
        String name = ctx.getLocalName();
1220
        if ("div".equals(name))
1221
          ret.addAll(getComponents(ctx));
1222
        else if (VOCABULARY.containsKey(name))
1223
          ret.add(ctx);
1224
      }
1225
    return ret;
1226
  }
1227
 
1228
  private static void transformToOneChildElement(Node node, String name)
1229
  {
1230
    if (node.getChildNodes().getLength() < 2)
1231
      return;
1232
    Document doc = node.getOwnerDocument();
1233
    Element child = doc.createElementNS(XMLConstants.RELAXNG_NS_URI, name);
1234
    Node ctx = getFirstChildElement(node);
1235
    while (ctx != null)
1236
      {
1237
        Node next = getNextSiblingElement(ctx);
1238
        child.appendChild(ctx);
1239
        ctx = next;
1240
      }
1241
    node.appendChild(child);
1242
  }
1243
 
1244
  private static Element getFirstChildElement(Node node)
1245
  {
1246
    Node ctx = node.getFirstChild();
1247
    while (ctx != null && ctx.getNodeType() != Node.ELEMENT_NODE)
1248
      ctx = ctx.getNextSibling();
1249
    return (Element) ctx;
1250
  }
1251
 
1252
  private static Element getNextSiblingElement(Node node)
1253
  {
1254
    Node ctx = node.getNextSibling();
1255
    while (ctx != null && ctx.getNodeType() != Node.ELEMENT_NODE)
1256
      ctx = ctx.getNextSibling();
1257
    return (Element) ctx;
1258
  }
1259
 
1260
  private static void forbidDescendants(Node node, Set names)
1261
    throws GrammarException
1262
  {
1263
    for (Node ctx = node.getFirstChild(); ctx != null;
1264
         ctx = ctx.getNextSibling())
1265
      {
1266
        String ns = ctx.getNamespaceURI();
1267
        if (!XMLConstants.RELAXNG_NS_URI.equals(ns))
1268
          continue;
1269
        String name = ctx.getLocalName();
1270
        if (names.contains(name))
1271
          throw new GrammarException("name not allowed: " + name);
1272
        forbidDescendants(ctx, names);
1273
      }
1274
  }
1275
 
1276
  private static boolean isDescendantOfFirstChildOfAttribute(Node node)
1277
  {
1278
    Node child = node;
1279
    Node parent = node.getParentNode();
1280
    while (parent != null && !"attribute".equals(parent.getLocalName()))
1281
      {
1282
        child = parent;
1283
        parent = child.getParentNode();
1284
      }
1285
    if (parent == null)
1286
      return false;
1287
    Node firstChild = getFirstChildElement(parent);
1288
    return firstChild == child;
1289
  }
1290
 
1291
  private static void combineNodes(Node node, String combine, String name,
1292
                                   List nodes)
1293
  {
1294
    Document doc = node.getOwnerDocument();
1295
    Node child =
1296
      doc.createElementNS(XMLConstants.RELAXNG_NS_URI, name);
1297
    Node combineNode =
1298
      doc.createElementNS(XMLConstants.RELAXNG_NS_URI, combine);
1299
    child.appendChild(combineNode);
1300
    boolean inserted = false;
1301
    for (Iterator i = nodes.iterator(); i.hasNext(); )
1302
      {
1303
        Node startNode = (Node) i.next();
1304
        if (!inserted)
1305
          {
1306
            node.insertBefore(child, startNode);
1307
            inserted = true;
1308
          }
1309
        Node ctx = startNode.getFirstChild();
1310
        while (ctx != null)
1311
          {
1312
            Node next = ctx.getNextSibling();
1313
            combineNode.appendChild(ctx);
1314
            ctx = next;
1315
          }
1316
        node.removeChild(startNode);
1317
      }
1318
  }
1319
 
1320
  Grammar parseGrammar(Element node)
1321
    throws GrammarException
1322
  {
1323
    checkName(node, "grammar");
1324
    Grammar grammar = new Grammar();
1325
    Element start = getFirstChildElement(node);
1326
    grammar.start = parsePattern(getFirstChildElement(start));
1327
    for (Element define = getNextSiblingElement(start); define != null;
1328
         define = getNextSiblingElement(define))
1329
      grammar.defines.add(parseDefine(define));
1330
    return grammar;
1331
  }
1332
 
1333
  Define parseDefine(Element node)
1334
    throws GrammarException
1335
  {
1336
    checkName(node, "define");
1337
    Define define = new Define();
1338
    define.name = node.getAttribute("name");
1339
    define.element = parseElement(getFirstChildElement(node));
1340
    return define;
1341
  }
1342
 
1343
  Pattern parseTop(Element node)
1344
    throws GrammarException
1345
  {
1346
    String name = node.getLocalName();
1347
    if ("notAllowed".equals(name))
1348
      return parseNotAllowed(node);
1349
    return parsePattern(node);
1350
  }
1351
 
1352
  Pattern parsePattern(Element node)
1353
    throws GrammarException
1354
  {
1355
    String name = node.getLocalName();
1356
    if ("empty".equals(name))
1357
      return parseEmpty(node);
1358
    return parseNonEmptyPattern(node);
1359
  }
1360
 
1361
  Pattern parseNonEmptyPattern(Element node)
1362
    throws GrammarException
1363
  {
1364
    String name = node.getLocalName();
1365
    if ("text".equals(name))
1366
      return parseText(node);
1367
    else if ("data".equals(name))
1368
      return parseData(node);
1369
    else if ("value".equals(name))
1370
      return parseValue(node);
1371
    else if ("list".equals(name))
1372
      return parseList(node);
1373
    else if ("attribute".equals(name))
1374
      return parseAttribute(node);
1375
    else if ("ref".equals(name))
1376
      return parseRef(node);
1377
    else if ("oneOrMore".equals(name))
1378
      return parseOneOrMore(node);
1379
    else if ("choice".equals(name))
1380
      return parseChoice(node);
1381
    else if ("group".equals(name))
1382
      return parseGroup(node);
1383
    else if ("interleave".equals(name))
1384
      return parseInterleave(node);
1385
    throw new GrammarException("invalid pattern: " + name);
1386
  }
1387
 
1388
  ElementPattern parseElement(Element node)
1389
    throws GrammarException
1390
  {
1391
    checkName(node, "element");
1392
    ElementPattern element = new ElementPattern();
1393
    Element nameClass = getFirstChildElement(node);
1394
    element.nameClass = parseNameClass(nameClass);
1395
    element.pattern = parseTop(getNextSiblingElement(nameClass));
1396
    return element;
1397
  }
1398
 
1399
  NotAllowedPattern parseNotAllowed(Element node)
1400
    throws GrammarException
1401
  {
1402
    checkName(node, "notAllowed");
1403
    return NotAllowedPattern.INSTANCE;
1404
  }
1405
 
1406
  EmptyPattern parseEmpty(Element node)
1407
    throws GrammarException
1408
  {
1409
    checkName(node, "empty");
1410
    return EmptyPattern.INSTANCE;
1411
  }
1412
 
1413
  TextPattern parseText(Element node)
1414
    throws GrammarException
1415
  {
1416
    checkName(node, "text");
1417
    return TextPattern.INSTANCE;
1418
  }
1419
 
1420
  DataPattern parseData(Element node)
1421
    throws GrammarException
1422
  {
1423
    checkName(node, "data");
1424
    DataPattern data = new DataPattern();
1425
    DatatypeLibrary dl =
1426
      getDatatypeLibrary(node.getAttribute("datatypeLibrary"));
1427
    String type = node.getAttribute("type");
1428
    try
1429
      {
1430
        data.type = dl.createDatatype(type);
1431
        data.datatypeLibrary = dl;
1432
      }
1433
    catch (DatatypeException e)
1434
      {
1435
        GrammarException e2 = new GrammarException(type);
1436
        e2.initCause(e);
1437
        throw e2;
1438
      }
1439
    Element ctx = getFirstChildElement(node);
1440
    while (ctx != null)
1441
      {
1442
        Element next = getNextSiblingElement(ctx);
1443
        String name = ctx.getLocalName();
1444
        if ("param".equals(name))
1445
          data.params.add(parseParam(ctx));
1446
        else if ("except".equals(name) && next == null)
1447
          data.exceptPattern = parsePattern(getFirstChildElement(ctx));
1448
        else
1449
          throw new GrammarException("invalid element: " + name);
1450
        ctx = next;
1451
      }
1452
    return data;
1453
  }
1454
 
1455
  Param parseParam(Element node)
1456
    throws GrammarException
1457
  {
1458
    checkName(node, "param");
1459
    Param param  = new Param();
1460
    param.name = node.getAttribute("name");
1461
    param.value = node.getTextContent();
1462
    return param;
1463
  }
1464
 
1465
  ValuePattern parseValue(Element node)
1466
    throws GrammarException
1467
  {
1468
    checkName(node, "value");
1469
    ValuePattern value = new ValuePattern();
1470
    DatatypeLibrary dl =
1471
      getDatatypeLibrary(node.getAttribute("datatypeLibrary"));
1472
    String type = node.getAttribute("type");
1473
    try
1474
      {
1475
        value.type = dl.createDatatype(type);
1476
        value.datatypeLibrary = dl;
1477
      }
1478
    catch (DatatypeException e)
1479
      {
1480
        GrammarException e2 = new GrammarException(type);
1481
        e2.initCause(e);
1482
        throw e2;
1483
      }
1484
    value.ns = node.getAttribute("ns");
1485
    value.value = node.getTextContent();
1486
    return value;
1487
  }
1488
 
1489
  ListPattern parseList(Element node)
1490
    throws GrammarException
1491
  {
1492
    checkName(node, "list");
1493
    ListPattern list = new ListPattern();
1494
    list.pattern = parsePattern(getFirstChildElement(node));
1495
    return list;
1496
  }
1497
 
1498
  AttributePattern parseAttribute(Element node)
1499
    throws GrammarException
1500
  {
1501
    checkName(node, "attribute");
1502
    AttributePattern attribute = new AttributePattern();
1503
    Element nameClass = getFirstChildElement(node);
1504
    attribute.nameClass = parseNameClass(nameClass);
1505
    attribute.pattern = parsePattern(getNextSiblingElement(nameClass));
1506
    return attribute;
1507
  }
1508
 
1509
  RefPattern parseRef(Element node)
1510
    throws GrammarException
1511
  {
1512
    checkName(node, "ref");
1513
    RefPattern ref = new RefPattern();
1514
    ref.name = node.getAttribute("name");
1515
    return ref;
1516
  }
1517
 
1518
  OneOrMorePattern parseOneOrMore(Element node)
1519
    throws GrammarException
1520
  {
1521
    checkName(node, "oneOrMore");
1522
    OneOrMorePattern oneOrMore = new OneOrMorePattern();
1523
    oneOrMore.pattern = parseNonEmptyPattern(getFirstChildElement(node));
1524
    return oneOrMore;
1525
  }
1526
 
1527
  ChoicePattern parseChoice(Element node)
1528
    throws GrammarException
1529
  {
1530
    checkName(node, "choice");
1531
    ChoicePattern choice = new ChoicePattern();
1532
    Element p1 = getFirstChildElement(node);
1533
    Element p2 = getNextSiblingElement(p1);
1534
    choice.pattern1 = parsePattern(p1);
1535
    choice.pattern2 = parseNonEmptyPattern(p2);
1536
    return choice;
1537
  }
1538
 
1539
  GroupPattern parseGroup(Element node)
1540
    throws GrammarException
1541
  {
1542
    checkName(node, "group");
1543
    GroupPattern group = new GroupPattern();
1544
    Element p1 = getFirstChildElement(node);
1545
    Element p2 = getNextSiblingElement(p1);
1546
    group.pattern1 = parseNonEmptyPattern(p1);
1547
    group.pattern2 = parseNonEmptyPattern(p2);
1548
    return group;
1549
  }
1550
 
1551
  InterleavePattern parseInterleave(Element node)
1552
    throws GrammarException
1553
  {
1554
    checkName(node, "interleave");
1555
    InterleavePattern interleave = new InterleavePattern();
1556
    Element p1 = getFirstChildElement(node);
1557
    Element p2 = getNextSiblingElement(p1);
1558
    interleave.pattern1 = parseNonEmptyPattern(p1);
1559
    interleave.pattern2 = parseNonEmptyPattern(p2);
1560
    return interleave;
1561
  }
1562
 
1563
  NameClass parseNameClass(Element node)
1564
    throws GrammarException
1565
  {
1566
    String name = node.getLocalName();
1567
    if ("anyName".equals(name))
1568
      return parseAnyName(node);
1569
    else if ("name".equals(name))
1570
      return parseName(node);
1571
    else if ("nsName".equals(name))
1572
      return parseNsName(node);
1573
    else if ("choice".equals(name))
1574
      return parseChoiceNameClass(node);
1575
    throw new GrammarException("invalid name class: " + name);
1576
  }
1577
 
1578
  AnyNameNameClass parseAnyName(Element node)
1579
    throws GrammarException
1580
  {
1581
    checkName(node, "anyName");
1582
    AnyNameNameClass anyName = new AnyNameNameClass();
1583
    Element except = getFirstChildElement(node);
1584
    if (except != null) {
1585
      checkName(except, "except");
1586
      anyName.exceptNameClass = parseNameClass(getFirstChildElement(except));
1587
    }
1588
    return anyName;
1589
  }
1590
 
1591
  NameNameClass parseName(Element node)
1592
    throws GrammarException
1593
  {
1594
    checkName(node, "name");
1595
    NameNameClass name = new NameNameClass();
1596
    name.ns = node.getAttribute("ns");
1597
    name.name = node.getTextContent();
1598
    return name;
1599
  }
1600
 
1601
  NSNameNameClass parseNsName(Element node)
1602
    throws GrammarException
1603
  {
1604
    checkName(node, "nsName");
1605
    NSNameNameClass nsName = new NSNameNameClass();
1606
    nsName.ns = node.getAttribute("ns");
1607
    Element except = getFirstChildElement(node);
1608
    if (except != null) {
1609
      checkName(except, "except");
1610
      nsName.exceptNameClass = parseNameClass(getFirstChildElement(except));
1611
    }
1612
    return nsName;
1613
  }
1614
 
1615
  ChoiceNameClass parseChoiceNameClass(Element node)
1616
    throws GrammarException
1617
  {
1618
    checkName(node, "choice");
1619
    ChoiceNameClass choice = new ChoiceNameClass();
1620
    Element c1 = getFirstChildElement(node);
1621
    Element c2 = getNextSiblingElement(c1);
1622
    choice.name1 = parseNameClass(c1);
1623
    choice.name2 = parseNameClass(c2);
1624
    return choice;
1625
  }
1626
 
1627
  void checkName(Element node, String name)
1628
    throws GrammarException
1629
  {
1630
    if (!name.equals(node.getLocalName()))
1631
      throw new GrammarException("expecting " + name);
1632
  }
1633
 
1634
  DatatypeLibrary getDatatypeLibrary(String uri)
1635
    throws GrammarException
1636
  {
1637
    if (datatypeLibraries == null)
1638
      datatypeLibraries = new HashMap();
1639
    DatatypeLibrary library = (DatatypeLibrary) datatypeLibraries.get(uri);
1640
    if (library == null)
1641
      {
1642
        library = new DatatypeLibraryLoader().createDatatypeLibrary(uri);
1643
        if (library == null)
1644
          throw new GrammarException("Datatype library not supported: " + uri);
1645
        datatypeLibraries.put(uri, library);
1646
      }
1647
    return library;
1648
  }
1649
 
1650
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.