Specifying indent and newline characters for JSON output?
Closed this issue · 5 comments
Hello,
Is there a way to control formatting characters in JSON like one can for XML?
// in XML
XMLEventWriter xmlWriter = XMLOutputFactory.newInstance().createXMLEventWriter(output);
xmlWriter = new PrettyXMLEventWriter(xmlWriter, " ", "\r\n"); // format output
xmlWriter.add(xmlReader);
But for JSON, similar code does not modify the formatting characters.
Is there a way to modify the JSON output in the same way?
For JSON output, indent and newline seem to be hardcoded in JsonStreamTargetImpl.
If not, I'd like to make this a feature request.
Thank you,
Dave
You are right, when using the default stream factory, pretty-printing cannot be customized. I'm taking this as a feature request. However, you can use the Jackson (or Gson) streaming backend and customize formatting there.
The default pretty-printer for Jackson uses two spaces and the system's line separator. If this what you want, just add the staxon-jackson
jar and you're done. To adjust Jackson's indentation, do something like this:
import java.io.IOException;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.impl.Indenter;
import org.codehaus.jackson.util.DefaultPrettyPrinter;
import de.odysseus.staxon.json.JsonXMLConfig;
import de.odysseus.staxon.json.JsonXMLConfigBuilder;
import de.odysseus.staxon.json.JsonXMLOutputFactory;
import de.odysseus.staxon.json.stream.JsonStreamFactory;
import de.odysseus.staxon.json.stream.jackson.JacksonStreamFactory;
public class CustomPrettyPrinting {
static class MyIndenter implements Indenter {
final String indent;
final String newline;
public MyIndenter() {
this("\t", System.getProperty("line.separator"));
}
public MyIndenter(String indent, String newline) {
this.indent = indent;
this.newline = newline;
}
@Override
public boolean isInline() {
return false;
}
@Override
public void writeIndentation(JsonGenerator jg, int level) throws IOException, JsonGenerationException {
jg.writeRaw(newline);
for (int i = 0; i < level; i++) {
jg.writeRaw(indent);
}
}
}
public static void main(String[] args) throws XMLStreamException {
JsonStreamFactory streamFactory = new JacksonStreamFactory() {
@Override
protected JsonGenerator configure(JsonGenerator generator, boolean pretty) {
generator = super.configure(generator, false);
if (pretty) {
DefaultPrettyPrinter prettyPrinter = new DefaultPrettyPrinter();
prettyPrinter.indentArraysWith(new MyIndenter());
prettyPrinter.indentObjectsWith(new MyIndenter());
generator.setPrettyPrinter(prettyPrinter);
}
return generator;
}
};
JsonXMLConfig config = new JsonXMLConfigBuilder().prettyPrint(true).build();
JsonXMLOutputFactory outputFactory = new JsonXMLOutputFactory(config, streamFactory);
XMLStreamWriter writer = outputFactory.createXMLStreamWriter(System.out);
writer.writeStartDocument();
writer.writeStartElement("alice");
writer.writeCharacters("bob");
writer.writeEndElement();
writer.writeEndDocument();
writer.close();
}
}
Hi Christoph,
Thank you for the feedback and for making configuration of JSON formatting
a feature request.
I'm looking forward to the enhancement. It will be a plus to be able to
apply formatting parameters consistently for XML and JSON.
Temporarily, I copied JsonStreamTargetImpl and changed the two values and
then extended JsonStreamFactoryImpl to return my JsonStreamTargetImpl.
I really like what you have developed. I'm working on code to convert
between JSON and XML without a loss of data and format both JSON and XML.
I have a second feature request and (I think) some bugs to report: The
enhancement is to make the JSON parse error messages more informative like
XML parse error messages.
For instance, the XML parser provides line number and column:
xmlErr = "value";
ParseError at [row,col]:[1,39]
Message: The end-tag for element type "test" must end with a '>' delimiter.
The JSON Parser has return:
java.io.IOException: Unexpected symbol: START_ARRAY - when an extra
[ is encountered.
Multiple roots within document - when parsing valid JSON with two
elements below opening {
In other cases, invalid JSON is parsed with out error. - for instance if
missing closing ] bracket, or } instead of closing ]
I have a number of examples that I can provide.
Please let me know if I can help.
Thank you,
Dave
On Fri, Jun 15, 2012 at 2:07 AM, Christoph Beck <
reply@reply.github.com
wrote:
You are right, when using the default stream factory, pretty-printing
cannot be customized. I'm taking this as a feature request. However, you
can use the Jackson (or Gson) streaming backend and customize formatting
there.
The default pretty-printer for Jackson uses two spaces and the system's
line separator. If this what you want, just add thestaxon-jackson
jar
and you're done. To adjust Jackson's indentation, do something like this:import java.io.IOException; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; import org.codehaus.jackson.JsonGenerationException; import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.impl.Indenter; import org.codehaus.jackson.util.DefaultPrettyPrinter; import de.odysseus.staxon.json.JsonXMLConfig; import de.odysseus.staxon.json.JsonXMLConfigBuilder; import de.odysseus.staxon.json.JsonXMLOutputFactory; import de.odysseus.staxon.json.stream.JsonStreamFactory; import de.odysseus.staxon.json.stream.jackson.JacksonStreamFactory; public class CustomPrettyPrinting { static class MyIndenter implements Indenter { final String indent; final String newline; public MyIndenter() { this("\t", System.getProperty("line.separator")); } public MyIndenter(String indent, String newline) { this.indent = indent; this.newline = newline; } @Override public boolean isInline() { return false; } @Override public void writeIndentation(JsonGenerator jg, int level) throws IOException, JsonGenerationException { jg.writeRaw(newline); for (int i = 0; i < level; i++) { jg.writeRaw(indent); } } } public static void main(String[] args) throws XMLStreamException { JsonStreamFactory streamFactory = new JacksonStreamFactory() { @Override protected JsonGenerator configure(JsonGenerator generator, boolean pretty) { generator = super.configure(generator, false); if (pretty) { DefaultPrettyPrinter prettyPrinter = new DefaultPrettyPrinter(); prettyPrinter.indentArraysWith(new MyIndenter()); prettyPrinter.indentObjectsWith(new MyIndenter()); generator.setPrettyPrinter(prettyPrinter); } return generator; } }; JsonXMLConfig config = new JsonXMLConfigBuilder().prettyPrint(true).build(); JsonXMLOutputFactory outputFactory = new JsonXMLOutputFactory(config, streamFactory); XMLStreamWriter writer = outputFactory.createXMLStreamWriter(System.out); writer.writeStartDocument(); writer.writeStartElement("alice"); writer.writeCharacters("bob"); writer.writeEndElement(); writer.writeEndDocument(); writer.close(); } }
Reply to this email directly or view it on GitHub:
#5 (comment)
Dave, would you please create separate issues?
- Add location (row/column) to parse exception messages
- Parser accepts invalid Json
A sample input, code snippet (or even better: unit test) demonstrating the problem would be nice.
Thanks!
Regarding multiple roots: this is possible with a "virtual root" (see wiki, virtualRoot
property).
Christoph,
Yes, I will add those as separate issues with code samples and I'll try to
include unit tests.
You are probably already aware, but http://jsonlint.com/ references an
open source JSON parser/validator that provides parse error line numbers.
Thanks for the pointing me to the "virtualRoot" property. I had imagined
that would be the way to solve that multiple root issue - obviously, you've
already thought of it.
Thanks!
Dave
On Sun, Jun 24, 2012 at 8:47 AM, Christoph Beck <
reply@reply.github.com
wrote:
Dave, would you please create separate issues?
- Add location (row/column) to parse exception messages
- Parser accepts invalid Json
A sample input, code snippet (or even better: unit test) demonstrating the
problem would be nice.Thanks!
Regarding multiple roots: this is possible with a "virtual root" (see
wiki,virtualRoot
property).
Reply to this email directly or view it on GitHub:
#5 (comment)
Added constructor for JsonStreamFactoryImpl
where you can pass prettySpace
, prettyIndent
and prettyNewline
strings. Now you can do:
JsonXMLConfig config = new JsonXMLConfigBuilder().prettyPrint(true).build();
JsonStreamFactory streamFactory = new JsonStreamFactoryImpl(" ", " ", "\n");
JsonXMLOutputFactory outputFactory = new JsonXMLOutputFactory(config, streamFactory);
XMLStreamWriter writer = outputFactory.createXMLStreamWriter(System.out);
writer.writeStartDocument();
writer.writeStartElement("alice");
writer.writeCharacters("bob");
writer.writeEndElement();
writer.writeEndDocument();
writer.close();