KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > xml > binding > DtdMarshaller


1 /*
2  * JBoss, the OpenSource J2EE webOS
3  *
4  * Distributable under LGPL license.
5  * See terms of license at gnu.org.
6  */

7 package org.jboss.xml.binding;
8
9 import com.wutka.dtd.DTD;
10 import com.wutka.dtd.DTDAttribute;
11 import com.wutka.dtd.DTDContainer;
12 import com.wutka.dtd.DTDElement;
13 import com.wutka.dtd.DTDEmpty;
14 import com.wutka.dtd.DTDItem;
15 import com.wutka.dtd.DTDMixed;
16 import com.wutka.dtd.DTDName;
17 import com.wutka.dtd.DTDPCData;
18 import com.wutka.dtd.DTDParser;
19 import com.wutka.dtd.DTDCardinal;
20 import org.jboss.logging.Logger;
21 import org.xml.sax.Attributes JavaDoc;
22 import org.xml.sax.SAXException JavaDoc;
23
24 import java.io.IOException JavaDoc;
25 import java.io.Reader JavaDoc;
26 import java.io.Writer JavaDoc;
27 import java.util.Collection JavaDoc;
28 import java.util.Collections JavaDoc;
29 import java.util.Enumeration JavaDoc;
30 import java.util.Hashtable JavaDoc;
31 import java.util.Iterator JavaDoc;
32 import java.util.LinkedList JavaDoc;
33
34
35 /**
36  * A DTD based org.jboss.xml.binding.Marshaller implementation.
37  *
38  * @author <a HREF="mailto:alex@jboss.org">Alexey Loubyansky</a>
39  * @version <tt>$Revision: 1.9.2.5 $</tt>
40  */

41 public class DtdMarshaller
42    extends AbstractMarshaller
43 {
44    private static final Logger log = Logger.getLogger(DtdMarshaller.class);
45
46    private String JavaDoc publicId;
47    private String JavaDoc systemId;
48
49    private final Stack stack = new StackImpl();
50    private DTD dtd;
51    private GenericObjectModelProvider provider;
52    private Content content = new Content();
53
54    private final LinkedList JavaDoc elementStack = new LinkedList JavaDoc();
55
56    public void mapPublicIdToSystemId(String JavaDoc publicId, String JavaDoc systemId)
57    {
58       this.publicId = publicId;
59       this.systemId = systemId;
60    }
61
62    public void marshal(Reader JavaDoc dtdReader, ObjectModelProvider provider, Object JavaDoc document, Writer JavaDoc writer)
63       throws IOException JavaDoc, SAXException JavaDoc
64    {
65       DTDParser parser = new DTDParser(dtdReader);
66       dtd = parser.parse(true);
67
68       this.provider = provider instanceof GenericObjectModelProvider ?
69          (GenericObjectModelProvider)provider : new DelegatingObjectModelProvider(provider);
70       //stack.push(document);
71

72       DTDElement[] roots = null;
73       if(dtd.rootElement != null)
74       {
75          handleRootElement(document, dtd.rootElement);
76       }
77       else
78       {
79          roots = getRootList(dtd);
80          for(int i = 0; i < roots.length; ++i)
81          {
82             handleRootElement(document, roots[i]);
83          }
84       }
85
86       //stack.pop();
87

88       // version & encoding
89
writeXmlVersion(writer);
90
91       // DOCTYPE
92
writer.write("<!DOCTYPE ");
93
94       if(dtd.rootElement != null)
95       {
96          writer.write(dtd.rootElement.getName());
97       }
98       else
99       {
100          for(int i = 0; i < roots.length; ++i)
101          {
102             writer.write(", ");
103             writer.write(roots[i].getName());
104          }
105       }
106
107       writer.write(" PUBLIC \"");
108       writer.write(publicId);
109       writer.write("\" \"");
110       writer.write(systemId);
111       writer.write("\">\n");
112
113       ContentWriter contentWriter = new ContentWriter(writer, propertyIsTrueOrNotSet(Marshaller.PROP_OUTPUT_INDENTATION));
114       content.handleContent(contentWriter);
115    }
116
117    private void handleRootElement(Object JavaDoc o, final DTDElement dtdRoot)
118    {
119       Element el = new Element(dtdRoot, true);
120       elementStack.addLast(el);
121       content.startDocument();
122
123       Object JavaDoc root = provider.getRoot(o, systemId, dtdRoot.getName());
124       if(root == null)
125       {
126          return;
127       }
128       stack.push(root);
129
130       Attributes JavaDoc attrs = provideAttributes(dtdRoot, root);
131       content.startElement("", dtdRoot.getName(), dtdRoot.getName(), attrs);
132       handleElement(dtd, dtdRoot, attrs);
133       content.endElement("", dtdRoot.getName(), dtdRoot.getName());
134
135       stack.pop();
136       content.endDocument();
137       elementStack.removeLast();
138    }
139
140    private final void handleElement(DTD dtd, DTDElement element, Attributes JavaDoc attrs)
141    {
142       DTDItem item = element.content;
143       if(item instanceof DTDMixed)
144       {
145          handleMixedElement((DTDMixed)item, element.getName(), attrs);
146       }
147       else if(item instanceof DTDEmpty)
148       {
149          final Object JavaDoc value = provider.getElementValue(stack.peek(), systemId, element.getName());
150          if(Boolean.TRUE.equals(value))
151          {
152             writeSkippedElements();
153             content.startElement("", element.getName(), element.getName(), attrs);
154             content.endElement("", element.getName(), element.getName());
155          }
156       }
157       else if(item instanceof DTDContainer)
158       {
159          processContainer(dtd, (DTDContainer)item);
160       }
161       else
162       {
163          throw new IllegalStateException JavaDoc("Unexpected element: " + element.getName());
164       }
165    }
166
167    private final void handleMixedElement(DTDMixed mixed, String JavaDoc elementName, Attributes JavaDoc attrs)
168    {
169       Object JavaDoc parent = stack.peek();
170       DTDItem[] items = mixed.getItems();
171       for(int i = 0; i < items.length; ++i)
172       {
173          DTDItem item = items[i];
174          if(item instanceof DTDPCData)
175          {
176             Object JavaDoc value = provider.getElementValue(parent, systemId, elementName);
177             if(value != null)
178             {
179                writeSkippedElements();
180
181                char[] ch = value.toString().toCharArray();
182                content.startElement("", elementName, elementName, attrs);
183                content.characters(ch, 0, ch.length);
184                content.endElement("", elementName, elementName);
185             }
186          }
187       }
188    }
189
190    private final void handleChildren(DTD dtd, DTDElement element, DTDCardinal elementCardinal)
191    {
192       Object JavaDoc parent = stack.peek();
193       Object JavaDoc children = provider.getChildren(parent, systemId, element.getName());
194
195       if(children != null)
196       {
197          Iterator JavaDoc iter;
198          if(children instanceof Iterator JavaDoc)
199          {
200             iter = (Iterator JavaDoc)children;
201          }
202          else if(children instanceof Collection JavaDoc)
203          {
204             iter = ((Collection JavaDoc)children).iterator();
205          }
206          else
207          {
208             iter = Collections.singletonList(children).iterator();
209          }
210
211          writeSkippedElements();
212
213          Element el = new Element(element, true);
214          elementStack.addLast(el);
215
216          final boolean singleValued = elementCardinal == DTDCardinal.NONE || elementCardinal == DTDCardinal.OPTIONAL;
217          if(singleValued)
218          {
219             // todo attributes!
220
content.startElement("", element.getName(), element.getName(), null);
221          }
222
223          while(iter.hasNext())
224          {
225             Object JavaDoc child = iter.next();
226             stack.push(child);
227
228             AttributesImpl attrs = (element.attributes.isEmpty() ? null : provideAttributes(element, child));
229             if(!singleValued)
230             {
231                content.startElement("", element.getName(), element.getName(), null);
232             }
233
234             handleElement(dtd, element, attrs);
235
236             if(!singleValued)
237             {
238                content.endElement(systemId, element.getName(), element.getName());
239             }
240
241             stack.pop();
242          }
243
244          if(singleValued)
245          {
246             content.endElement(systemId, element.getName(), element.getName());
247          }
248
249          elementStack.removeLast();
250       }
251       else
252       {
253          boolean removeLast = false;
254          if(!(element.getContent() instanceof DTDMixed || element.getContent() instanceof DTDEmpty))
255          {
256             Element el = new Element(element);
257             elementStack.addLast(el);
258             removeLast = true;
259          }
260
261          AttributesImpl attrs = (element.attributes.isEmpty() ? null : provideAttributes(element, parent));
262          handleElement(dtd, element, attrs);
263
264          if(removeLast)
265          {
266             Element el = (Element)elementStack.removeLast();
267             if(el.started)
268             {
269                DTDElement started = el.element;
270                content.endElement("", started.getName(), started.getName());
271             }
272          }
273       }
274    }
275
276    private final void processContainer(DTD dtd, DTDContainer container)
277    {
278       DTDItem[] items = container.getItems();
279       for(int i = 0; i < items.length; ++i)
280       {
281          DTDItem item = items[i];
282          if(item instanceof DTDContainer)
283          {
284             processContainer(dtd, (DTDContainer)item);
285          }
286          else if(item instanceof DTDName)
287          {
288             DTDName name = (DTDName)item;
289             DTDElement element = (DTDElement)dtd.elements.get(name.value);
290             handleChildren(dtd, element, name.getCardinal());
291          }
292       }
293    }
294
295    private void writeSkippedElements()
296    {
297       Element el = (Element)elementStack.getLast();
298       if(!el.started)
299       {
300          int firstNotStarted = elementStack.size() - 1;
301          do
302          {
303             el = (Element)elementStack.get(--firstNotStarted);
304          }
305          while(!el.started);
306
307          ++firstNotStarted;
308
309          while(firstNotStarted < elementStack.size())
310          {
311             el = (Element)elementStack.get(firstNotStarted++);
312             DTDElement notStarted = el.element;
313
314             if(log.isTraceEnabled())
315             {
316                log.trace("starting skipped> " + notStarted.getName());
317             }
318
319             content.startElement("", notStarted.getName(), notStarted.getName(), null);
320             el.started = true;
321          }
322       }
323    }
324
325    private AttributesImpl provideAttributes(DTDElement element, Object JavaDoc container)
326    {
327       final Hashtable JavaDoc attributes = element.attributes;
328       AttributesImpl attrs = new AttributesImpl(attributes.size());
329
330       for(Iterator JavaDoc attrIter = attributes.values().iterator(); attrIter.hasNext();)
331       {
332          DTDAttribute attr = (DTDAttribute)attrIter.next();
333          final Object JavaDoc attrValue = provider.getAttributeValue(container, systemId, attr.getName());
334
335          if(attrValue != null)
336          {
337             attrs.add(systemId,
338                attr.getName(),
339                attr.getName(),
340                attr.getType().toString(),
341                attrValue.toString()
342             );
343          }
344       }
345
346       return attrs;
347    }
348
349    /**
350     * @param dtd the DTD object model
351     * @return root element names
352     */

353    protected static DTDElement[] getRootList(DTD dtd)
354    {
355       Hashtable JavaDoc roots = new Hashtable JavaDoc();
356       Enumeration JavaDoc e = dtd.elements.elements();
357       while(e.hasMoreElements())
358       {
359          DTDElement element = (DTDElement)e.nextElement();
360          roots.put(element.name, element);
361       }
362
363       e = dtd.elements.elements();
364       while(e.hasMoreElements())
365       {
366          DTDElement element = (DTDElement)e.nextElement();
367          if(!(element.content instanceof DTDContainer))
368          {
369             continue;
370          }
371
372          Enumeration JavaDoc items = ((DTDContainer)element.content).getItemsVec().elements();
373          while(items.hasMoreElements())
374          {
375             removeElements(roots, dtd, (DTDItem)items.nextElement());
376          }
377       }
378
379       final Collection JavaDoc rootCol = roots.values();
380       return (DTDElement[])rootCol.toArray(new DTDElement[rootCol.size()]);
381    }
382
383    protected static void removeElements(Hashtable JavaDoc h, DTD dtd, DTDItem item)
384    {
385       if(item instanceof DTDName)
386       {
387          h.remove(((DTDName)item).value);
388       }
389       else if(item instanceof DTDContainer)
390       {
391          Enumeration JavaDoc e = ((DTDContainer)item).getItemsVec().elements();
392          while(e.hasMoreElements())
393          {
394             removeElements(h, dtd, (DTDItem)e.nextElement());
395          }
396       }
397    }
398
399    // Inner
400

401    private static final class Element
402    {
403       public final DTDElement element;
404       public boolean started;
405
406       public Element(DTDElement element, boolean started)
407       {
408          this.element = element;
409          this.started = started;
410       }
411
412       public Element(DTDElement element)
413       {
414          this.element = element;
415       }
416
417       public String JavaDoc toString()
418       {
419          return "[element=" + element.getName() + ", started=" + started + "]";
420       }
421    }
422 }
423
Popular Tags