1
|
|
/*
|
2
|
|
* JBind
|
3
|
|
*
|
4
|
|
* Copyright (c) by Stefan Wachter. All rights reserved.
|
5
|
|
*
|
6
|
|
* Usage, modification, and redistribution is subject to license terms that are
|
7
|
|
* available at 'http://www.jbind.org'. The JBind license is like the
|
8
|
|
* 'Apache Software License V 1.1'.
|
9
|
|
*/
|
10
|
|
package org.jbind.xml.schema.element;
|
11
|
|
|
12
|
|
import java.io.InputStream;
|
13
|
|
import java.net.URL;
|
14
|
|
import java.util.Iterator;
|
15
|
|
import java.util.Map;
|
16
|
|
|
17
|
|
import org.jbind.message.IMessage;
|
18
|
|
import org.jbind.util.collection.UnsynchronizedStack;
|
19
|
|
import org.jbind.util.other.StrBuffer;
|
20
|
|
import org.jbind.xml.base.ILocation;
|
21
|
|
import org.jbind.xml.base.InputSourceLocation;
|
22
|
|
import org.jbind.xml.base.WhiteSpaceProcessing;
|
23
|
|
import org.jbind.xml.core.bridge.IRegEx;
|
24
|
|
import org.jbind.xml.core.bridge.IRegExFactory;
|
25
|
|
import org.jbind.xml.core.bridge.IXPath;
|
26
|
|
import org.jbind.xml.core.bridge.IXPathFactory;
|
27
|
|
import org.jbind.xml.msg.IConstraintViolations;
|
28
|
|
import org.jbind.xml.msg.XmlException;
|
29
|
|
import org.jbind.xml.msg.XmlMessages;
|
30
|
|
import org.jbind.xml.parser.AttributeData;
|
31
|
|
import org.jbind.xml.parser.IContentHandler;
|
32
|
|
import org.jbind.xml.parser.IErrorHandler;
|
33
|
|
import org.jbind.xml.parser.INamespaceContext;
|
34
|
|
import org.jbind.xml.parser.InputSourceParser;
|
35
|
|
import org.jbind.xml.parser.QualifiedName;
|
36
|
|
import org.jbind.xml.schema.instantiation.IElemValHelper;
|
37
|
|
import org.jbind.xml.schema.instantiation.ISchemaElement;
|
38
|
|
import org.jbind.xml.schema.instantiation.ISchemaParser;
|
39
|
|
import org.xml.sax.EntityResolver;
|
40
|
|
import org.xml.sax.InputSource;
|
41
|
|
|
42
|
|
public class SchemaParser implements ISchemaParser, IElemValHelper, IContentHandler, IErrorHandler {
|
43
|
|
|
44
|
|
private EntityResolver myEntityResolver;
|
45
|
|
private IXPathFactory myXPathFactory;
|
46
|
|
private IRegExFactory myRegExFactory;
|
47
|
|
|
48
|
|
private UnsynchronizedStack myStack = null;
|
49
|
|
|
50
|
|
private StrBuffer myCharacterBuffer = new StrBuffer();
|
51
|
|
private ILocation myCharacterLocation = null;
|
52
|
|
private Map myCharacterPrefixMappings = null;
|
53
|
|
|
54
|
|
private IConstraintViolations myViolations = null;
|
55
|
|
|
56
|
|
private ISchemaDocument myDocument = null;
|
57
|
|
private SchemaElement mySchemaElement = null;
|
58
|
|
private ISchemaElement myParentSchemaElement = null;
|
59
|
|
|
60
|
|
private int myIgnoreElements = 0;
|
61
|
|
|
62
|
|
private InputSourceParser myParser = new InputSourceParser();
|
63
|
|
|
64
|
175
|
public SchemaParser(EntityResolver anEntityResolver, IXPathFactory anXPathFactory, IRegExFactory aRegExFactory) {
|
65
|
175
|
myEntityResolver = anEntityResolver;
|
66
|
175
|
myXPathFactory = anXPathFactory;
|
67
|
175
|
myRegExFactory = aRegExFactory;
|
68
|
|
}
|
69
|
|
|
70
|
243
|
private void prepare() {
|
71
|
243
|
myStack = new UnsynchronizedStack();
|
72
|
243
|
myDocument = null;
|
73
|
243
|
myIgnoreElements = 0;
|
74
|
|
}
|
75
|
|
|
76
|
243
|
public synchronized ISchemaElement parseSchema(URL anUrl, ISchemaElement aParent) throws XmlException {
|
77
|
243
|
myViolations = XmlMessages.constraintViolations();
|
78
|
243
|
myParentSchemaElement = aParent;
|
79
|
243
|
prepare();
|
80
|
243
|
try {
|
81
|
243
|
InputStream inputStream = anUrl.openStream();
|
82
|
243
|
InputSource inputSource = new InputSource(inputStream);
|
83
|
243
|
inputSource.setSystemId(anUrl.toString());
|
84
|
243
|
myParser.parse(inputSource, this, this, myEntityResolver);
|
85
|
|
} catch (Exception e) {
|
86
|
0
|
throw new XmlException(XmlMessages.wrappedException(e, null));
|
87
|
|
}
|
88
|
243
|
if (!myViolations.isEmpty()) {
|
89
|
39
|
throw new XmlException(myViolations);
|
90
|
|
}
|
91
|
204
|
return myDocument.getSchemaElement();
|
92
|
|
}
|
93
|
|
|
94
|
18181
|
private UnsynchronizedStack getStack() {
|
95
|
18181
|
return myStack;
|
96
|
|
}
|
97
|
|
|
98
|
0
|
public ISchemaDocument getDocument() {
|
99
|
0
|
return myDocument;
|
100
|
|
}
|
101
|
|
|
102
|
243
|
public void startDocument(InputSource anInputSource, INamespaceContext aNamespaceContext) {
|
103
|
243
|
myDocument = new SchemaDocument();
|
104
|
243
|
getStack().push(myDocument);
|
105
|
|
}
|
106
|
|
|
107
|
243
|
public void endDocument(InputSource anInputSource, INamespaceContext aNamespaceContext) {
|
108
|
243
|
if (myCharacterBuffer.length() > 0) {
|
109
|
241
|
addTextChild();
|
110
|
|
}
|
111
|
|
}
|
112
|
|
|
113
|
5928
|
public void startElement(QualifiedName aQName, Map anAttributes, int aLine, int aColumn, InputSource anInputSource, INamespaceContext aNamespaceContext) throws Exception {
|
114
|
5928
|
if (myIgnoreElements > 0) {
|
115
|
0
|
myIgnoreElements++;
|
116
|
0
|
return;
|
117
|
|
}
|
118
|
|
|
119
|
5928
|
addTextChild();
|
120
|
|
|
121
|
5928
|
Map prefixMapping = aNamespaceContext.getCurrentMapping();
|
122
|
|
|
123
|
5928
|
IParent parent = (IParent)getStack().peek();
|
124
|
|
// Determine the parent element. The root element has no parent.
|
125
|
5928
|
IElement parentElement = (parent instanceof IElement) ? (IElement)parent : null;
|
126
|
|
|
127
|
5928
|
ILocation location = new InputSourceLocation(anInputSource, aLine, aColumn);
|
128
|
|
|
129
|
5928
|
IElement element = null;
|
130
|
|
|
131
|
5928
|
CreationParams creationParams = new CreationParams(myDocument, location, parentElement, prefixMapping, aQName);
|
132
|
|
|
133
|
5928
|
try {
|
134
|
5928
|
if (null == parentElement) {
|
135
|
243
|
mySchemaElement = new SchemaElement(creationParams, myParentSchemaElement);
|
136
|
243
|
element = mySchemaElement;
|
137
|
|
} else {
|
138
|
5685
|
element = ((IElement)parentElement).createChild(creationParams, myViolations);
|
139
|
|
}
|
140
|
5928
|
parent.addChild(element);
|
141
|
|
|
142
|
5928
|
for (Iterator i = anAttributes.values().iterator(); i.hasNext(); ) {
|
143
|
7304
|
AttributeData ad = (AttributeData)i.next();
|
144
|
7304
|
String attQName = "".equals(ad.qn.getPrefix()) ? ad.qn.getLocalPart() : ad.qn.getPrefix() + ":" + ad.qn.getLocalPart();
|
145
|
7304
|
String attNamespace = ad.qn.getNamespace();
|
146
|
7304
|
String attLocalName = ad.qn.getLocalPart();
|
147
|
7304
|
String attValue = ad.value;
|
148
|
7304
|
try {
|
149
|
7304
|
ACParams acParams = new ACParams(attQName, attNamespace, attLocalName, attValue, location, prefixMapping, mySchemaElement);
|
150
|
7304
|
element.addAttribute(acParams);
|
151
|
|
} catch (XmlException e) {
|
152
|
6
|
myViolations.add(e.getXmlMessage());
|
153
|
|
}
|
154
|
|
}
|
155
|
|
} catch (XmlException e) {
|
156
|
0
|
myViolations.add(e.getXmlMessage());
|
157
|
0
|
myIgnoreElements++;
|
158
|
|
}
|
159
|
|
|
160
|
5928
|
getStack().push(element);
|
161
|
|
}
|
162
|
|
|
163
|
5928
|
public void endElement(QualifiedName aQName, Map anAttributes, int aLine, int aColumn, InputSource anInputSource, INamespaceContext aNamespaceContext) throws Exception {
|
164
|
5928
|
if (myIgnoreElements > 0) {
|
165
|
0
|
myIgnoreElements--;
|
166
|
0
|
if (myIgnoreElements == 0) {
|
167
|
0
|
myCharacterBuffer.setLength(0);
|
168
|
|
}
|
169
|
0
|
return;
|
170
|
|
}
|
171
|
|
|
172
|
5928
|
addTextChild();
|
173
|
|
|
174
|
5928
|
IElement element = (IElement)getStack().pop();
|
175
|
|
|
176
|
5928
|
element.validateElement(this, myViolations);
|
177
|
|
}
|
178
|
|
|
179
|
12097
|
private void addTextChild() {
|
180
|
|
// White space is collapsed
|
181
|
12097
|
String s = WhiteSpaceProcessing.COLLAPSE.process(myCharacterBuffer.toString());
|
182
|
12097
|
if (s.length() > 0) {
|
183
|
154
|
IParent parent = (IParent)getStack().peek();
|
184
|
154
|
IElement parentElement = (parent instanceof IElement) ? (IElement)parent : null;
|
185
|
154
|
IText text = new Text(s);
|
186
|
154
|
if (null != text) {
|
187
|
154
|
text.setLocation(myCharacterLocation);
|
188
|
154
|
parent.addChild(text);
|
189
|
|
}
|
190
|
154
|
myCharacterBuffer.setLength(0);
|
191
|
|
}
|
192
|
12097
|
myCharacterPrefixMappings = null;
|
193
|
|
}
|
194
|
|
|
195
|
8886
|
public void text(String aString, int aLine, int aColumn, InputSource anInputSource, INamespaceContext aNamespaceContext) throws Exception {
|
196
|
8886
|
if (myCharacterBuffer.length() == 0) {
|
197
|
328
|
myCharacterLocation = new InputSourceLocation(anInputSource, aLine, aColumn);
|
198
|
328
|
myCharacterPrefixMappings = aNamespaceContext.getCurrentMapping();
|
199
|
|
}
|
200
|
8886
|
myCharacterBuffer.append(aString);
|
201
|
|
}
|
202
|
|
|
203
|
0
|
public void startXInclude(String aParseMethod, URL aUrl, String aFragementId) {}
|
204
|
0
|
public void endXInclude() {}
|
205
|
|
|
206
|
30
|
public IRegEx createRegEx(String aRegEx) throws Exception {
|
207
|
30
|
return myRegExFactory.createRegEx(aRegEx);
|
208
|
|
}
|
209
|
|
|
210
|
147
|
public IXPath createXPath(String anXPath, Map aPrefixMappings, boolean aRestrictedForm) throws Exception {
|
211
|
147
|
return myXPathFactory.createXPath(anXPath, aPrefixMappings, aRestrictedForm);
|
212
|
|
}
|
213
|
|
|
214
|
0
|
public void fatalError(IMessage aMessage) {
|
215
|
0
|
myViolations.add(aMessage);
|
216
|
|
}
|
217
|
|
|
218
|
0
|
public boolean error(IMessage aMessage) {
|
219
|
0
|
myViolations.add(aMessage);
|
220
|
0
|
return false;
|
221
|
|
}
|
222
|
|
|
223
|
0
|
public boolean warning(IMessage aMessage) {
|
224
|
0
|
myViolations.add(aMessage);
|
225
|
0
|
return false;
|
226
|
|
}
|
227
|
|
|
228
|
0
|
public void exception(Exception anException, InputSource anInputSource) {
|
229
|
0
|
anException.printStackTrace();
|
230
|
0
|
myViolations.add(XmlMessages.wrappedException(anException, new InputSourceLocation(anInputSource)));
|
231
|
|
}
|
232
|
|
}
|
233
|
|
|