All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.javacrumbs.json2xml.JsonSaxAdapter Maven / Gradle / Ivy

There is a newer version: 4.2
Show newest version
/*
 * Copyright 2011 the original author or authors.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *       http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.javacrumbs.json2xml;

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

import java.io.IOException;

import static com.fasterxml.jackson.core.JsonToken.END_ARRAY;
import static com.fasterxml.jackson.core.JsonToken.END_OBJECT;
import static com.fasterxml.jackson.core.JsonToken.FIELD_NAME;
import static com.fasterxml.jackson.core.JsonToken.START_ARRAY;
import static com.fasterxml.jackson.core.JsonToken.START_OBJECT;
import static com.fasterxml.jackson.core.JsonToken.VALUE_NULL;

/**
 * Converts JSON to SAX events. It can be used either directly
 * 
 *  
 * 	ContentHandler ch = ...;
 * 	JsonSaxAdapter adapter = new JsonSaxAdapter(JsonSaxAdapterTest.JSON, ch);
 * 	adapter.parse();
 *  
 *  
* * or using {@link JsonXmlReader} *
 *  
 * 	Transformer transformer = TransformerFactory.newInstance().newTransformer();
 * 	InputSource source = new InputSource(...);
 * 	Result result = ...;
 * 	transformer.transform(new SAXSource(new JsonXmlReader(),source), result);
 *  
 *  
*/ public class JsonSaxAdapter { private static final AttributesImpl EMPTY_ATTRIBUTES = new AttributesImpl(); private final JsonParser jsonParser; private final ContentHandler contentHandler; private final String namespaceUri; private final boolean addTypeAttributes; private final String artificialRootName; private final ElementNameConverter nameConverter; private static final JsonFactory JSON_FACTORY = new JsonFactory(); /** * Creates JsonSaxAdapter that coverts JSON to SAX events. * @param json JSON to parse * @param contentHandler target of SAX events */ public JsonSaxAdapter(final String json, final ContentHandler contentHandler) { this(parseJson(json), contentHandler); } /** * Creates JsonSaxAdapter that coverts JSON to SAX events. * @param jsonParser parsed JSON * @param contentHandler target of SAX events */ public JsonSaxAdapter(final JsonParser jsonParser, final ContentHandler contentHandler) { this(jsonParser, contentHandler, ""); } /** * Creates JsonSaxAdapter that coverts JSON to SAX events. * @param jsonParser parsed JSON * @param contentHandler target of SAX events * @param namespaceUri namespace of the generated XML */ public JsonSaxAdapter(final JsonParser jsonParser, final ContentHandler contentHandler, final String namespaceUri) { this(jsonParser, contentHandler, namespaceUri, false); } /** * Creates JsonSaxAdapter that coverts JSON to SAX events. * @param jsonParser parsed JSON * @param contentHandler target of SAX events * @param namespaceUri namespace of the generated XML * @param addTypeAttributes adds type information as attributes */ public JsonSaxAdapter(final JsonParser jsonParser, final ContentHandler contentHandler, final String namespaceUri, final boolean addTypeAttributes) { this(jsonParser, contentHandler, namespaceUri, addTypeAttributes, null); } /** * Creates JsonSaxAdapter that coverts JSON to SAX events. * @param jsonParser parsed JSON * @param contentHandler target of SAX events * @param namespaceUri namespace of the generated XML * @param addTypeAttributes adds type information as attributes * @param artificialRootName if set, an artificial root is generated so JSON documents with more roots can be handeled. */ public JsonSaxAdapter(final JsonParser jsonParser, final ContentHandler contentHandler, final String namespaceUri, final boolean addTypeAttributes, final String artificialRootName) { this(jsonParser, contentHandler, namespaceUri, addTypeAttributes, artificialRootName, null); } /** * Creates JsonSaxAdapter that coverts JSON to SAX events. * @param jsonParser parsed JSON * @param contentHandler target of SAX events * @param namespaceUri namespace of the generated XML * @param addTypeAttributes adds type information as attributes * @param artificialRootName if set, an artificial root is generated so JSON documents with more roots can be handeled. */ public JsonSaxAdapter(final JsonParser jsonParser, final ContentHandler contentHandler, final String namespaceUri, final boolean addTypeAttributes, final String artificialRootName, final ElementNameConverter nameConverter) { this.jsonParser = jsonParser; this.contentHandler = contentHandler; this.namespaceUri = namespaceUri; this.addTypeAttributes = addTypeAttributes; this.artificialRootName = artificialRootName; this.nameConverter = nameConverter; contentHandler.setDocumentLocator(new DocumentLocator()); } private static JsonParser parseJson(final String json) { try { return JSON_FACTORY.createParser(json); } catch (Exception e) { throw new ParserException("Parsing error", e); } } /** * Method parses JSON and emits SAX events. */ public void parse() throws ParserException { try { jsonParser.nextToken(); contentHandler.startDocument(); if (shouldAddArtificialRoot()) { startElement(artificialRootName); parseElement(artificialRootName, false); endElement(artificialRootName); } else if (START_OBJECT.equals(jsonParser.getCurrentToken())) { int elementsWritten = parseObject(); if (elementsWritten>1) { throw new ParserException("More than one root element. Can not generate legal XML. You can set artificialRootName to generate an artificial root."); } } else { throw new ParserException("Unsupported root element. Can not generate legal XML. You can set artificialRootName to generate an artificial root."); } contentHandler.endDocument(); } catch (Exception e) { throw new ParserException("Parsing error: " + e.getMessage(), e); } } private boolean shouldAddArtificialRoot() { return artificialRootName != null && artificialRootName.length() > 0; } /** * Parses generic object. * * @return number of elements written * @throws IOException * @throws JsonParseException * @throws Exception */ private int parseObject() throws Exception { int elementsWritten = 0; while (jsonParser.nextToken() != null && jsonParser.getCurrentToken() != END_OBJECT) { if (FIELD_NAME.equals(jsonParser.getCurrentToken())) { String elementName = convertName(jsonParser.getCurrentName()); //jump to element value jsonParser.nextToken(); startElement(elementName); parseElement(elementName, false); endElement(elementName); elementsWritten++; } else { throw new ParserException("Error when parsing. Expected field name got " + jsonParser.getCurrentToken()); } } return elementsWritten; } private String convertName(String name) { if (nameConverter != null) { return nameConverter.convertName(name); } else { return name; } } /** * Pares JSON element. * @param elementName * @param inArray if the element is in an array * @throws Exception */ private void parseElement(final String elementName, final boolean inArray) throws Exception { JsonToken currentToken = jsonParser.getCurrentToken(); if (START_OBJECT.equals(currentToken)) { parseObject(); } else if (START_ARRAY.equals(currentToken)) { if (inArray) { startElement(elementName); parseArray(elementName); endElement(elementName); } else { parseArray(elementName); } } else if (currentToken.isScalarValue()) { if (inArray) { startElement(elementName); parseValue(); endElement(elementName); } else { parseValue(); } } } private void parseArray(final String elementName) throws Exception { while (jsonParser.nextToken() != END_ARRAY && jsonParser.getCurrentToken() != null) { parseElement(elementName, true); } } private void parseValue() throws Exception { if (VALUE_NULL != jsonParser.getCurrentToken()) { String text = jsonParser.getText(); contentHandler.characters(text.toCharArray(), 0, text.length()); } } private void startElement(final String elementName) throws SAXException { contentHandler.startElement(namespaceUri, elementName, elementName, getTypeAttributes()); } protected Attributes getTypeAttributes() { if (addTypeAttributes) { String currentTokenType = getCurrentTokenType(); if (currentTokenType != null) { AttributesImpl attributes = new AttributesImpl(); attributes.addAttribute("", "type", "type", "string", currentTokenType); return attributes; } else { return EMPTY_ATTRIBUTES; } } else { return EMPTY_ATTRIBUTES; } } protected String getCurrentTokenType() { switch (jsonParser.getCurrentToken()) { case VALUE_NUMBER_INT: return "int"; case VALUE_NUMBER_FLOAT: return "float"; case VALUE_FALSE: return "boolean"; case VALUE_TRUE: return "boolean"; case VALUE_STRING: return "string"; case VALUE_NULL: return "null"; case START_ARRAY: return "array"; default: return null; } } private void endElement(final String elementName) throws SAXException { contentHandler.endElement(namespaceUri, elementName, elementName); } public static class ParserException extends RuntimeException { private static final long serialVersionUID = 2194022343599245018L; public ParserException(final String message, final Throwable cause) { super(message, cause); } public ParserException(final String message) { super(message); } public ParserException(final Throwable cause) { super(cause); } } private class DocumentLocator implements Locator { public String getPublicId() { Object sourceRef = jsonParser.getCurrentLocation().getSourceRef(); if (sourceRef != null) { return sourceRef.toString(); } else { return ""; } } public String getSystemId() { return getPublicId(); } public int getLineNumber() { return jsonParser.getCurrentLocation() != null ? jsonParser.getCurrentLocation().getLineNr() : -1; } public int getColumnNumber() { return jsonParser.getCurrentLocation() != null ? jsonParser.getCurrentLocation().getColumnNr() : -1; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy