From c245ed48de6090914f24f15bb21bbd6b6c00c2ed Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Sun, 10 Sep 2023 21:48:42 +0200 Subject: [PATCH] Fix stax writer to generate nicer XML --- src/mdo/writer-stax.vm | 107 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 101 insertions(+), 6 deletions(-) diff --git a/src/mdo/writer-stax.vm b/src/mdo/writer-stax.vm index e71dc42c35..fbe696fa89 100644 --- a/src/mdo/writer-stax.vm +++ b/src/mdo/writer-stax.vm @@ -72,6 +72,7 @@ import org.apache.maven.internal.xml.XmlNodeBuilder; import ${packageModelV4}.${class.name}; #end #end +import org.codehaus.stax2.util.StreamWriterDelegate; @Generated public class ${className} { @@ -96,6 +97,8 @@ public class ${className} { private String fileComment = null; #if ( $locationTracking ) + private boolean addLocationInformation = true; + /** * Field stringFormatter. */ @@ -116,6 +119,13 @@ public class ${className} { } //-- void setFileComment(String) #if ( $locationTracking ) + /** + * Method setAddLocationInformation. + */ + public void setAddLocationInformation(boolean addLocationInformation) { + this.addLocationInformation = addLocationInformation; + } //-- void setAddLocationInformation(String) + /** * Method setStringFormatter. * @@ -136,7 +146,9 @@ public class ${className} { public void write(Writer writer, ${root.name} ${rootLcapName}) throws IOException, XMLStreamException { XMLOutputFactory factory = new com.ctc.wstx.stax.WstxOutputFactory(); factory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, false); - XMLStreamWriter serializer = factory.createXMLStreamWriter(writer); + factory.setProperty(com.ctc.wstx.api.WstxOutputProperties.P_USE_DOUBLE_QUOTES_IN_XML_DECL, true); + factory.setProperty(com.ctc.wstx.api.WstxOutputProperties.P_ADD_SPACE_AFTER_EMPTY_ELEM, true); + XMLStreamWriter serializer = new IndentingXMLStreamWriter(factory.createXMLStreamWriter(writer)); serializer.writeStartDocument(${rootLcapName}.getModelEncoding(), null); write${root.name}("$rootTag", ${rootLcapName}, serializer); serializer.writeEndDocument(); @@ -152,7 +164,9 @@ public class ${className} { public void write(OutputStream stream, ${root.name} ${rootLcapName}) throws IOException, XMLStreamException { XMLOutputFactory factory = new com.ctc.wstx.stax.WstxOutputFactory(); factory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, false); - XMLStreamWriter serializer = factory.createXMLStreamWriter(stream, ${rootLcapName}.getModelEncoding()); + factory.setProperty(com.ctc.wstx.api.WstxOutputProperties.P_USE_DOUBLE_QUOTES_IN_XML_DECL, true); + factory.setProperty(com.ctc.wstx.api.WstxOutputProperties.P_ADD_SPACE_AFTER_EMPTY_ELEM, true); + XMLStreamWriter serializer = new IndentingXMLStreamWriter(factory.createXMLStreamWriter(stream, ${rootLcapName}.getModelEncoding())); serializer.writeStartDocument(${rootLcapName}.getModelEncoding(), null); write${root.name}("$rootTag", ${rootLcapName}, serializer); serializer.writeEndDocument(); @@ -168,7 +182,9 @@ public class ${className} { if (${classLcapName} != null) { #if ( $class == $root ) if (this.fileComment != null) { + serializer.writeCharacters("\n"); serializer.writeComment(this.fileComment); + serializer.writeCharacters("\n"); } serializer.writeStartElement("", tagName, NAMESPACE); serializer.writeNamespace("", NAMESPACE); @@ -315,7 +331,12 @@ public class ${className} { if (dom != null) { serializer.writeStartElement(NAMESPACE, dom.getName()); for (Map.Entry attr : dom.getAttributes().entrySet()) { - serializer.writeAttribute(NAMESPACE, attr.getKey(), attr.getValue()); + if (attr.getKey().startsWith("xml:")) { + serializer.writeAttribute("http://www.w3.org/XML/1998/namespace", + attr.getKey().substring(4), attr.getValue()); + } else { + serializer.writeAttribute(attr.getKey(), attr.getValue()); + } } for (XmlNode child : dom.getChildren()) { writeDom(child, serializer); @@ -364,9 +385,11 @@ public class ${className} { * @throws IOException */ protected void writeLocationTracking(InputLocationTracker locationTracker, Object key, XMLStreamWriter serializer) throws IOException, XMLStreamException { - InputLocation location = (locationTracker == null) ? null : locationTracker.getLocation(key); - if (location != null) { - serializer.writeComment(toString(location)); + if (addLocationInformation) { + InputLocation location = (locationTracker == null) ? null : locationTracker.getLocation(key); + if (location != null) { + serializer.writeComment(toString(location)); + } } } //-- void writeLocationTracking(InputLocationTracker, Object, XMLStreamWriter) @@ -383,4 +406,76 @@ public class ${className} { return ' ' + location.getSource().toString() + ':' + location.getLineNumber() + ' '; } //-- String toString(InputLocation) #end + + static class IndentingXMLStreamWriter extends StreamWriterDelegate { + + int depth = 0; + boolean hasChildren = false; + + public IndentingXMLStreamWriter(XMLStreamWriter parent) { + super(parent); + } + + @Override + public void writeEmptyElement(String localName) throws XMLStreamException { + indent(); + super.writeEmptyElement(localName); + hasChildren = true; + } + + @Override + public void writeEmptyElement(String namespaceURI, String localName) throws XMLStreamException { + indent(); + super.writeEmptyElement(namespaceURI, localName); + hasChildren = true; + } + + @Override + public void writeEmptyElement(String prefix, String localName, String namespaceURI) throws XMLStreamException { + indent(); + super.writeEmptyElement(prefix, localName, namespaceURI); + hasChildren = true; + } + + @Override + public void writeStartElement(String localName) throws XMLStreamException { + indent(); + super.writeStartElement(localName); + depth++; + hasChildren = false; + } + + @Override + public void writeStartElement(String namespaceURI, String localName) throws XMLStreamException { + indent(); + super.writeStartElement(namespaceURI, localName); + depth++; + hasChildren = false; + } + + @Override + public void writeStartElement(String prefix, String localName, String namespaceURI) throws XMLStreamException { + indent(); + super.writeStartElement(prefix, localName, namespaceURI); + depth++; + hasChildren = false; + } + + @Override + public void writeEndElement() throws XMLStreamException { + depth--; + if (hasChildren) { + indent(); + } + super.writeEndElement(); + hasChildren = true; + } + + private void indent() throws XMLStreamException { + super.writeCharacters("\n"); + for (int i = 0; i < depth; i++) { + super.writeCharacters(" "); + } + } + } }