View Javadoc
1   package org.codehaus.modello.plugin.sax;
2   
3   /*
4    * Copyright (c) 2013, Codehaus.org
5    *
6    * Permission is hereby granted, free of charge, to any person obtaining a copy of
7    * this software and associated documentation files (the "Software"), to deal in
8    * the Software without restriction, including without limitation the rights to
9    * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
10   * of the Software, and to permit persons to whom the Software is furnished to do
11   * so, subject to the following conditions:
12   *
13   * The above copyright notice and this permission notice shall be included in all
14   * copies or substantial portions of the Software.
15   *
16   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22   * SOFTWARE.
23   */
24  
25  import javax.inject.Named;
26  
27  import java.io.IOException;
28  import java.util.List;
29  import java.util.Map;
30  
31  import org.codehaus.modello.ModelloException;
32  import org.codehaus.modello.model.Model;
33  import org.codehaus.modello.model.ModelAssociation;
34  import org.codehaus.modello.model.ModelClass;
35  import org.codehaus.modello.model.ModelDefault;
36  import org.codehaus.modello.model.ModelField;
37  import org.codehaus.modello.plugin.java.javasource.JClass;
38  import org.codehaus.modello.plugin.java.javasource.JConstructor;
39  import org.codehaus.modello.plugin.java.javasource.JField;
40  import org.codehaus.modello.plugin.java.javasource.JMethod;
41  import org.codehaus.modello.plugin.java.javasource.JParameter;
42  import org.codehaus.modello.plugin.java.javasource.JSourceCode;
43  import org.codehaus.modello.plugin.java.javasource.JSourceWriter;
44  import org.codehaus.modello.plugin.java.javasource.JType;
45  import org.codehaus.modello.plugin.java.metadata.JavaFieldMetadata;
46  import org.codehaus.modello.plugin.model.ModelClassMetadata;
47  import org.codehaus.modello.plugins.xml.AbstractXmlJavaGenerator;
48  import org.codehaus.modello.plugins.xml.metadata.XmlAssociationMetadata;
49  import org.codehaus.modello.plugins.xml.metadata.XmlFieldMetadata;
50  import org.codehaus.modello.plugins.xml.metadata.XmlModelMetadata;
51  
52  /**
53   * @since 1.8
54   * @author <a href="mailto:simonetripodi@apache.org">Simone Tripodi</a>
55   */
56  @Named("sax-writer")
57  public class SaxWriterGenerator extends AbstractXmlJavaGenerator {
58  
59      private boolean requiresDomSupport;
60  
61      @Override
62      public void generate(Model model, Map<String, Object> parameters) throws ModelloException {
63          initialize(model, parameters);
64  
65          requiresDomSupport = false;
66  
67          try {
68              generateSaxWriter();
69          } catch (IOException ex) {
70              throw new ModelloException("Exception while generating SAX Writer.", ex);
71          }
72      }
73  
74      private void generateSaxWriter() throws ModelloException, IOException {
75          Model objectModel = getModel();
76  
77          String packageName =
78                  objectModel.getDefaultPackageName(isPackageWithVersion(), getGeneratedVersion()) + ".io.sax";
79  
80          String marshallerName = getFileName("SaxWriter");
81  
82          JSourceWriter sourceWriter = newJSourceWriter(packageName, marshallerName);
83  
84          JClass jClass = new JClass(packageName + '.' + marshallerName);
85          initHeader(jClass);
86          suppressAllWarnings(objectModel, jClass);
87  
88          jClass.addImport("java.io.IOException");
89          jClass.addImport("java.io.OutputStream");
90          jClass.addImport("java.io.OutputStreamWriter");
91          jClass.addImport("java.io.UnsupportedEncodingException");
92          jClass.addImport("java.io.Writer");
93          jClass.addImport("java.util.Iterator");
94          jClass.addImport("java.util.Properties");
95          jClass.addImport("javax.xml.transform.OutputKeys");
96          jClass.addImport("javax.xml.transform.TransformerException");
97          jClass.addImport("javax.xml.transform.TransformerFactory");
98          jClass.addImport("javax.xml.transform.sax.SAXTransformerFactory");
99          jClass.addImport("javax.xml.transform.sax.TransformerHandler");
100         jClass.addImport("javax.xml.transform.stream.StreamResult");
101         jClass.addImport("org.xml.sax.ContentHandler");
102         jClass.addImport("org.xml.sax.SAXException");
103         jClass.addImport("org.xml.sax.helpers.AttributesImpl");
104 
105         JField namespaceField = new JField(new JClass("String"), "NAMESPACE");
106         namespaceField.getModifiers().setFinal(true);
107         namespaceField.getModifiers().setStatic(true);
108         namespaceField.setInitString("\"\"");
109         jClass.addField(namespaceField);
110 
111         JField factoryField = new JField(new JClass("SAXTransformerFactory"), "transformerFactory");
112         factoryField.getModifiers().setFinal(true);
113         factoryField.setInitString("(SAXTransformerFactory) TransformerFactory.newInstance()");
114         jClass.addField(factoryField);
115 
116         addModelImports(jClass, null);
117 
118         String root = objectModel.getRoot(getGeneratedVersion());
119 
120         ModelClass rootClass = objectModel.getClass(root, getGeneratedVersion());
121 
122         String rootElement = resolveTagName(rootClass);
123 
124         JConstructor saxWriterConstructor = new JConstructor(jClass);
125         JSourceCode sc = saxWriterConstructor.getSourceCode();
126         sc.add("transformerFactory.setAttribute( \"indent-number\", 2 );");
127 
128         jClass.addConstructor(saxWriterConstructor);
129 
130         // ----------------------------------------------------------------------
131         // Write the write( Writer, Model ) method which will do the unmarshalling.
132         // ----------------------------------------------------------------------
133 
134         JMethod marshall = new JMethod("write");
135 
136         String rootElementParameterName = uncapitalise(root);
137         marshall.addParameter(new JParameter(new JClass("Writer"), "writer"));
138         marshall.addParameter(new JParameter(new JClass(root), rootElementParameterName));
139 
140         marshall.addException(new JClass("SAXException"));
141         marshall.addException(new JClass("TransformerException"));
142 
143         sc = marshall.getSourceCode();
144 
145         sc.add("TransformerHandler transformerHandler = transformerFactory.newTransformerHandler();");
146 
147         sc.add("Properties format = new Properties();");
148         sc.add("format.put( OutputKeys.ENCODING, " + rootElementParameterName + ".getModelEncoding() );");
149         sc.add("format.put( OutputKeys.INDENT, \"yes\" );");
150         sc.add("format.put( OutputKeys.MEDIA_TYPE, \"text/xml\" );");
151         sc.add("format.put( OutputKeys.METHOD, \"xml\" );");
152 
153         sc.add("transformerHandler.getTransformer().setOutputProperties( format );");
154         sc.add("transformerHandler.setResult( new StreamResult( writer ) );");
155 
156         sc.add("write( transformerHandler, " + rootElementParameterName + " );");
157 
158         jClass.addMethod(marshall);
159 
160         // ----------------------------------------------------------------------
161         // Write the write( OutputStream, Model ) method which will do the unmarshalling.
162         // ----------------------------------------------------------------------
163 
164         marshall = new JMethod("write");
165 
166         marshall.addParameter(new JParameter(new JClass("OutputStream"), "stream"));
167         marshall.addParameter(new JParameter(new JClass(root), rootElementParameterName));
168 
169         marshall.addException(new JClass("SAXException"));
170         marshall.addException(new JClass("TransformerException"));
171         marshall.addException(new JClass("UnsupportedEncodingException"));
172 
173         sc = marshall.getSourceCode();
174 
175         sc.add("write( new OutputStreamWriter( stream, " + rootElementParameterName + ".getModelEncoding() ), "
176                 + rootElementParameterName + " );");
177 
178         jClass.addMethod(marshall);
179 
180         // ----------------------------------------------------------------------
181         // Write the write( ContentHandler, Model ) method which will do the unmarshalling.
182         // ----------------------------------------------------------------------
183 
184         marshall = new JMethod("write");
185 
186         marshall.addParameter(new JParameter(new JClass("ContentHandler"), "contentHandler"));
187         marshall.addParameter(new JParameter(new JClass(root), rootElementParameterName));
188 
189         marshall.addException(new JClass("SAXException"));
190 
191         sc = marshall.getSourceCode();
192 
193         sc.add("write( contentHandler, " + rootElementParameterName + ", true );");
194 
195         jClass.addMethod(marshall);
196 
197         // ----------------------------------------------------------------------
198         // Write the write( ContentHandler, Model, boolean ) method which will do the unmarshalling.
199         // ----------------------------------------------------------------------
200 
201         marshall = new JMethod("write");
202 
203         marshall.addParameter(new JParameter(new JClass("ContentHandler"), "contentHandler"));
204         marshall.addParameter(new JParameter(new JClass(root), rootElementParameterName));
205         marshall.addParameter(new JParameter(JType.BOOLEAN, "startDocument"));
206 
207         marshall.addException(new JClass("SAXException"));
208 
209         sc = marshall.getSourceCode();
210 
211         sc.add("if ( startDocument )");
212         sc.add("{");
213         sc.addIndented("contentHandler.startDocument();");
214         sc.add("}");
215 
216         sc.add("AttributesImpl attributes = new AttributesImpl();");
217 
218         sc.add("write" + root + "( " + rootElementParameterName + ", \"" + rootElement
219                 + "\", contentHandler, attributes );");
220 
221         sc.add("if ( startDocument )");
222         sc.add("{");
223         sc.addIndented("contentHandler.endDocument();");
224         sc.add("}");
225 
226         jClass.addMethod(marshall);
227 
228         // ----------------------------------------------------------------------
229         // Write the writeText( String, ContentHandler ) method which will help unmarshalling textual values.
230         // ----------------------------------------------------------------------
231 
232         marshall = new JMethod("writeText");
233         marshall.getModifiers().makePrivate();
234 
235         marshall.addParameter(new JParameter(new JClass("String"), "text"));
236         marshall.addParameter(new JParameter(new JClass("ContentHandler"), "contentHandler"));
237 
238         marshall.addException(new JClass("SAXException"));
239 
240         sc = marshall.getSourceCode();
241 
242         sc.add("contentHandler.characters( text.toCharArray(), 0, text.length() );");
243 
244         // generate the code
245 
246         jClass.addMethod(marshall);
247 
248         writeAllClasses(objectModel, jClass);
249 
250         if (requiresDomSupport) {
251             createWriteDomMethod(jClass);
252             createXpp3DomMethod(jClass);
253         }
254 
255         jClass.print(sourceWriter);
256 
257         sourceWriter.close();
258     }
259 
260     private void writeAllClasses(Model objectModel, JClass jClass) throws ModelloException {
261         for (ModelClass clazz : getClasses(objectModel)) {
262             writeClass(clazz, jClass);
263         }
264     }
265 
266     private void writeClass(ModelClass modelClass, JClass jClass) throws ModelloException {
267         String className = modelClass.getName();
268 
269         String uncapClassName = uncapitalise(className);
270 
271         JMethod marshall = new JMethod("write" + className);
272 
273         marshall.addParameter(new JParameter(new JClass(className), uncapClassName));
274         marshall.addParameter(new JParameter(new JClass("String"), "tagName"));
275         marshall.addParameter(new JParameter(new JClass("ContentHandler"), "contentHandler"));
276         marshall.addParameter(new JParameter(new JClass("AttributesImpl"), "attributes"));
277 
278         marshall.addException(new JClass("SAXException"));
279 
280         marshall.getModifiers().makePrivate();
281 
282         JSourceCode sc = marshall.getSourceCode();
283 
284         ModelClassMetadata classMetadata = (ModelClassMetadata) modelClass.getMetadata(ModelClassMetadata.ID);
285 
286         String namespace = null;
287         XmlModelMetadata xmlModelMetadata =
288                 (XmlModelMetadata) modelClass.getModel().getMetadata(XmlModelMetadata.ID);
289 
290         ModelField contentField = null;
291 
292         String contentValue = null;
293 
294         List<ModelField> modelFields = getFieldsForXml(modelClass, getGeneratedVersion());
295 
296         boolean needsToCleanAttributes = false;
297 
298         // XML attributes
299         for (ModelField field : modelFields) {
300             XmlFieldMetadata xmlFieldMetadata = (XmlFieldMetadata) field.getMetadata(XmlFieldMetadata.ID);
301 
302             JavaFieldMetadata javaFieldMetadata = (JavaFieldMetadata) field.getMetadata(JavaFieldMetadata.ID);
303 
304             String fieldTagName = resolveTagName(field, xmlFieldMetadata);
305 
306             String type = field.getType();
307 
308             String value = uncapClassName + "." + getPrefix(javaFieldMetadata) + capitalise(field.getName()) + "()";
309 
310             if (xmlFieldMetadata.isContent()) {
311                 contentField = field;
312                 contentValue = value;
313                 continue;
314             }
315 
316             if (xmlFieldMetadata.isAttribute()) {
317                 sc.add(getValueChecker(type, value, field));
318 
319                 sc.add("{");
320                 sc.addIndented("attributes.addAttribute( NAMESPACE, \""
321                         + fieldTagName
322                         + "\", \""
323                         + fieldTagName
324                         + "\", \"CDATA\", "
325                         + getValue(field.getType(), value, xmlFieldMetadata)
326                         + " );");
327                 sc.add("}");
328 
329                 needsToCleanAttributes = true;
330             }
331         }
332 
333         // add namespace information for root element only
334         if (classMetadata.isRootElement() && (xmlModelMetadata.getNamespace() != null)) {
335             namespace = xmlModelMetadata.getNamespace(getGeneratedVersion());
336             sc.add("contentHandler.startPrefixMapping( \"\", \"" + namespace + "\" );");
337         }
338 
339         if ((namespace != null) && (xmlModelMetadata.getSchemaLocation() != null)) {
340             String url = xmlModelMetadata.getSchemaLocation(getGeneratedVersion());
341 
342             sc.add("contentHandler.startPrefixMapping( \"xsi\", \"http://www.w3.org/2001/XMLSchema-instance\" );");
343 
344             sc.add(
345                     "attributes.addAttribute( \"http://www.w3.org/2001/XMLSchema-instance\", \"schemaLocation\", \"xsi:schemaLocation\", \"CDATA\", \""
346                             + namespace + " " + url + "\" );");
347         }
348 
349         sc.add("contentHandler.startElement( NAMESPACE, tagName, tagName, attributes );");
350 
351         if (needsToCleanAttributes) {
352             sc.add("attributes.clear();");
353         }
354 
355         if (contentField != null) {
356             XmlFieldMetadata xmlFieldMetadata = (XmlFieldMetadata) contentField.getMetadata(XmlFieldMetadata.ID);
357             sc.add("writeText( " + getValue(contentField.getType(), contentValue, xmlFieldMetadata)
358                     + ", contentHandler );");
359         }
360 
361         // XML tags
362         for (ModelField field : modelFields) {
363             XmlFieldMetadata xmlFieldMetadata = (XmlFieldMetadata) field.getMetadata(XmlFieldMetadata.ID);
364 
365             if (xmlFieldMetadata.isContent()) {
366                 // skip field with type Content
367                 continue;
368             }
369 
370             JavaFieldMetadata javaFieldMetadata = (JavaFieldMetadata) field.getMetadata(JavaFieldMetadata.ID);
371 
372             String fieldTagName = resolveTagName(field, xmlFieldMetadata);
373 
374             String type = field.getType();
375 
376             String value = uncapClassName + "." + getPrefix(javaFieldMetadata) + capitalise(field.getName()) + "()";
377 
378             if (xmlFieldMetadata.isAttribute()) {
379                 continue;
380             }
381 
382             if (field instanceof ModelAssociation) {
383                 ModelAssociation association = (ModelAssociation) field;
384 
385                 String associationName = association.getName();
386 
387                 if (association.isOneMultiplicity()) {
388                     sc.add(getValueChecker(type, value, association));
389 
390                     sc.add("{");
391                     sc.addIndented("write" + association.getTo() + "( (" + association.getTo() + ") " + value + ", \""
392                             + fieldTagName + "\", contentHandler, attributes );");
393                     sc.add("}");
394                 } else {
395                     // MANY_MULTIPLICITY
396 
397                     XmlAssociationMetadata xmlAssociationMetadata =
398                             (XmlAssociationMetadata) association.getAssociationMetadata(XmlAssociationMetadata.ID);
399 
400                     String valuesTagName = resolveTagName(fieldTagName, xmlAssociationMetadata);
401 
402                     type = association.getType();
403                     String toType = association.getTo();
404 
405                     boolean wrappedItems = xmlAssociationMetadata.isWrappedItems();
406 
407                     if (ModelDefault.LIST.equals(type) || ModelDefault.SET.equals(type)) {
408                         sc.add(getValueChecker(type, value, association));
409 
410                         sc.add("{");
411                         sc.indent();
412 
413                         if (wrappedItems) {
414                             sc.add("contentHandler.startElement( NAMESPACE, \"" + fieldTagName + "\", \"" + fieldTagName
415                                     + "\", attributes );");
416                         }
417 
418                         sc.add("for ( Iterator iter = " + value + ".iterator(); iter.hasNext(); )");
419 
420                         sc.add("{");
421                         sc.indent();
422 
423                         if (isClassInModel(association.getTo(), modelClass.getModel())) {
424                             sc.add(toType + " o = (" + toType + ") iter.next();");
425 
426                             sc.add("write" + toType + "( o, \"" + valuesTagName + "\", contentHandler, attributes );");
427                         } else {
428                             sc.add(toType + " " + singular(uncapitalise(field.getName())) + " = (" + toType
429                                     + ") iter.next();");
430 
431                             sc.add("contentHandler.startElement( NAMESPACE, \"" + valuesTagName + "\", \""
432                                     + valuesTagName + "\", attributes );");
433                             sc.add("writeText( " + singular(uncapitalise(field.getName())) + ", contentHandler );");
434                             sc.add("contentHandler.endElement( NAMESPACE, \"" + valuesTagName + "\", \"" + valuesTagName
435                                     + "\" );");
436                         }
437 
438                         sc.unindent();
439                         sc.add("}");
440 
441                         if (wrappedItems) {
442                             sc.add("contentHandler.endElement( NAMESPACE, \"" + fieldTagName + "\", \"" + fieldTagName
443                                     + "\" );");
444                         }
445 
446                         sc.unindent();
447                         sc.add("}");
448                     } else {
449                         // Map or Properties
450 
451                         sc.add(getValueChecker(type, value, field));
452 
453                         sc.add("{");
454                         sc.indent();
455 
456                         if (wrappedItems) {
457                             sc.add("contentHandler.startElement( NAMESPACE, \"" + fieldTagName + "\", \"" + fieldTagName
458                                     + "\", attributes );");
459                         }
460 
461                         sc.add("for ( Iterator iter = " + value + ".keySet().iterator(); iter.hasNext(); )");
462 
463                         sc.add("{");
464                         sc.indent();
465 
466                         sc.add("String key = (String) iter.next();");
467 
468                         sc.add(association.getTo() + " value = (" + association.getTo() + ") " + value
469                                 + ".get( key );");
470 
471                         if (xmlAssociationMetadata.isMapExplode()) {
472                             sc.add("contentHandler.startElement( NAMESPACE, \"" + singular(associationName) + "\", \""
473                                     + singular(associationName) + "\", attributes );");
474 
475                             sc.add("contentHandler.startElement( NAMESPACE, \"key\", \"key\", attributes );");
476                             sc.add("writeText( key, contentHandler );");
477                             sc.add("contentHandler.endElement( NAMESPACE, \"key\", \"key\" );");
478 
479                             if (isClassInModel(
480                                     association.getTo(),
481                                     association.getModelClass().getModel())) {
482                                 sc.add("write" + association.getTo()
483                                         + "( value, \"value\", contentHandler, attributes );");
484                             } else {
485                                 sc.add("contentHandler.startElement( NAMESPACE, \"value\", \"value\", attributes );");
486                                 sc.add("writeText( " + getValue(association.getTo(), "value", xmlFieldMetadata)
487                                         + ", contentHandler );");
488                                 sc.add("contentHandler.endElement( NAMESPACE, \"value\", \"value\" );");
489                             }
490 
491                             sc.add("contentHandler.endElement( NAMESPACE, \"" + singular(associationName) + "\", \""
492                                     + singular(associationName) + "\" );");
493                         } else {
494                             if (isClassInModel(
495                                     association.getTo(),
496                                     association.getModelClass().getModel())) {
497                                 sc.add("write" + association.getTo() + "( value, key, contentHandler, attributes );");
498                             } else {
499                                 sc.add("contentHandler.startElement( NAMESPACE, key, key, attributes );");
500                                 sc.add("writeText( " + getValue(association.getTo(), "value", xmlFieldMetadata)
501                                         + ", contentHandler );");
502                                 sc.add("contentHandler.endElement( NAMESPACE, key, key );");
503                             }
504                         }
505 
506                         sc.unindent();
507                         sc.add("}");
508 
509                         if (wrappedItems) {
510                             sc.add("contentHandler.endElement( NAMESPACE, \"" + fieldTagName + "\", \"" + fieldTagName
511                                     + "\" );");
512                         }
513 
514                         sc.unindent();
515                         sc.add("}");
516                     }
517                 }
518             } else {
519                 sc.add(getValueChecker(type, value, field));
520 
521                 sc.add("{");
522                 if ("DOM".equals(field.getType())) {
523                     if (domAsXpp3) {
524                         sc.addIndented("writeDom( (Xpp3Dom) " + value + ", contentHandler, attributes );");
525                     } else {
526                         sc.addIndented("writeDom( (Element) " + value + ", contentHandler );");
527                     }
528 
529                     requiresDomSupport = true;
530                 } else {
531                     sc.indent();
532                     sc.add("contentHandler.startElement( NAMESPACE, \"" + fieldTagName + "\", \"" + fieldTagName
533                             + "\", attributes );");
534                     sc.add("writeText( " + getValue(field.getType(), value, xmlFieldMetadata) + ", contentHandler );");
535                     sc.add("contentHandler.endElement( NAMESPACE, \"" + fieldTagName + "\", \"" + fieldTagName
536                             + "\" );");
537                     sc.unindent();
538                 }
539                 sc.add("}");
540             }
541         }
542 
543         sc.add("contentHandler.endElement( NAMESPACE, tagName, tagName );");
544 
545         jClass.addMethod(marshall);
546     }
547 
548     private void createXpp3DomMethod(JClass jClass) {
549         jClass.addImport("org.codehaus.plexus.util.xml.Xpp3Dom");
550 
551         JMethod method = new JMethod("writeDom");
552         method.getModifiers().makePrivate();
553 
554         method.addParameter(new JParameter(new JType("Xpp3Dom"), "dom"));
555         method.addParameter(new JParameter(new JClass("ContentHandler"), "contentHandler"));
556         method.addParameter(new JParameter(new JClass("AttributesImpl"), "attributes"));
557 
558         method.addException(new JClass("SAXException"));
559 
560         JSourceCode sc = method.getSourceCode();
561 
562         sc.add("String[] attributeNames = dom.getAttributeNames();");
563         sc.add("if ( attributeNames != null && attributeNames.length > 0 )");
564         sc.add("{");
565         sc.indent();
566         sc.add("String attributeName;");
567         sc.add("String attributeValue;");
568         sc.add("for ( int i = 0; i < attributeNames.length; i++ )");
569         sc.add("{");
570         sc.indent();
571         sc.add("attributeName = attributeNames[i];");
572         sc.add("attributeValue = dom.getAttribute( attributeName );");
573         sc.add("attributes.addAttribute( NAMESPACE, attributeName, attributeName, \"CDATA\", attributeValue );");
574         sc.unindent();
575         sc.add("}");
576         sc.unindent();
577         sc.add("}");
578 
579         sc.add("contentHandler.startElement( NAMESPACE, dom.getName(), dom.getName(), attributes );");
580 
581         sc.add("if ( attributeNames != null && attributeNames.length > 0 )");
582         sc.add("{");
583         sc.addIndented("attributes.clear();");
584         sc.add("}");
585 
586         sc.add("Xpp3Dom[] children = dom.getChildren();");
587         sc.add("if ( children != null &&  children.length > 0 )");
588         sc.add("{");
589         sc.indent();
590         sc.add("for ( int i = 0; i < children.length; i++ )");
591         sc.add("{");
592         sc.addIndented("writeDom( children[i], contentHandler, attributes );");
593         sc.add("}");
594         sc.unindent();
595         sc.add("}");
596 
597         sc.add("String value = dom.getValue();");
598         sc.add("if ( value != null )");
599         sc.add("{");
600         sc.addIndented("writeText( value, contentHandler );");
601         sc.add("}");
602         sc.add("contentHandler.endElement( NAMESPACE, dom.getName(), dom.getName() );");
603 
604         jClass.addMethod(method);
605     }
606 
607     private void createWriteDomMethod(JClass jClass) {
608         jClass.addImport("org.w3c.dom.Element");
609         jClass.addImport("javax.xml.transform.Transformer");
610         jClass.addImport("javax.xml.transform.dom.DOMSource");
611         jClass.addImport("javax.xml.transform.sax.SAXResult");
612 
613         JMethod method = new JMethod("writeDom");
614         method.getModifiers().makePrivate();
615 
616         method.addParameter(new JParameter(new JType("Element"), "dom"));
617         method.addParameter(new JParameter(new JClass("ContentHandler"), "contentHandler"));
618 
619         method.addException(new JClass("SAXException"));
620 
621         JSourceCode sc = method.getSourceCode();
622 
623         sc.add("try");
624         sc.add("{");
625         sc.indent();
626         sc.add("Transformer transformer = transformerFactory.newTransformer();");
627         sc.add("DOMSource source = new DOMSource( dom );");
628         sc.add("SAXResult result = new SAXResult( contentHandler );");
629         sc.add("transformer.transform( source, result );");
630         sc.unindent();
631         sc.add("}");
632 
633         sc.add("catch ( TransformerException e )");
634         sc.add("{");
635         sc.addIndented("throw new SAXException( \"Impossible to convert DOM element, see nested exceptions.\", e );");
636         sc.add("}");
637 
638         jClass.addMethod(method);
639     }
640 }