diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractFormattable.java b/jOOQ/src/main/java/org/jooq/impl/AbstractFormattable.java index b0cf07a719..3189c346e6 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractFormattable.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractFormattable.java @@ -219,6 +219,8 @@ abstract class AbstractFormattable implements Formattable, Serializable { formatCSV(writer, new CSVFormat().header(header).delimiter(delimiter).nullString(nullString)); } + abstract JSONFormat defaultJSONFormat(); + @Override public final String formatJSON() { StringWriter writer = new StringWriter(); @@ -245,12 +247,14 @@ abstract class AbstractFormattable implements Formattable, Serializable { @Override public final void formatJSON(Writer writer) { - formatJSON(writer, null); + formatJSON(writer, defaultJSONFormat()); } + abstract XMLFormat defaultXMLFormat(); + @Override public final String formatXML() { - return formatXML((XMLFormat) null); + return formatXML(defaultXMLFormat()); } @Override @@ -262,7 +266,7 @@ abstract class AbstractFormattable implements Formattable, Serializable { @Override public final void formatXML(OutputStream stream) { - formatXML(stream, null); + formatXML(stream, defaultXMLFormat()); } @Override @@ -272,7 +276,7 @@ abstract class AbstractFormattable implements Formattable, Serializable { @Override public final void formatXML(Writer writer) { - formatXML(writer, null); + formatXML(writer, defaultXMLFormat()); } @Override @@ -342,11 +346,11 @@ abstract class AbstractFormattable implements Formattable, Serializable { @Override public final Document intoXML() { - return intoXML((XMLFormat) null); + return intoXML(defaultXMLFormat()); } @Override public final H intoXML(H handler) throws SAXException { - return intoXML(handler, null); + return intoXML(handler, defaultXMLFormat()); } } diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java b/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java index 5a1b6a74f5..92ebb6bac3 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java @@ -1050,10 +1050,12 @@ abstract class AbstractRecord extends AbstractStore implements Record { } @Override - public final void formatJSON(Writer writer, JSONFormat format) { - if (format == null) - format = JSONFormat.DEFAULT_FOR_RECORDS; + final JSONFormat defaultJSONFormat() { + return JSONFormat.DEFAULT_FOR_RECORDS; + } + @Override + public final void formatJSON(Writer writer, JSONFormat format) { if (format.header()) log.debug("JSONFormat.header currently not supported for Record.formatJSON()"); @@ -1075,10 +1077,12 @@ abstract class AbstractRecord extends AbstractStore implements Record { } @Override - public final void formatXML(Writer writer, XMLFormat format) { - if (format == null) - format = XMLFormat.DEFAULT_FOR_RECORDS; + final XMLFormat defaultXMLFormat() { + return XMLFormat.DEFAULT_FOR_RECORDS; + } + @Override + public final void formatXML(Writer writer, XMLFormat format) { if (format.header()) log.debug("XMLFormat.header currently not supported for Record.formatXML()"); diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractResult.java b/jOOQ/src/main/java/org/jooq/impl/AbstractResult.java index 7e3ab1c2ab..90f4b3ef9e 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractResult.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractResult.java @@ -49,6 +49,7 @@ import static org.jooq.tools.StringUtils.abbreviate; import static org.jooq.tools.StringUtils.leftPad; import static org.jooq.tools.StringUtils.rightPad; +import java.io.StringReader; import java.io.Writer; import java.sql.Date; import java.sql.Timestamp; @@ -99,11 +100,15 @@ import org.jooq.tools.StringUtils; import org.jooq.tools.json.JSONValue; import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; import org.w3c.dom.Element; +import org.w3c.dom.NodeList; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; +import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; +import org.xml.sax.helpers.DefaultHandler; /** * @author Lukas Eder @@ -611,10 +616,12 @@ abstract class AbstractResult extends AbstractFormattable impl } @Override - public final void formatJSON(Writer writer, JSONFormat format) { - if (format == null) - format = JSONFormat.DEFAULT_FOR_RESULTS; + final JSONFormat defaultJSONFormat() { + return JSONFormat.DEFAULT_FOR_RESULTS; + } + @Override + public final void formatJSON(Writer writer, JSONFormat format) { try { String separator; int recordLevel = format.header() ? 2 : 1; @@ -857,10 +864,12 @@ abstract class AbstractResult extends AbstractFormattable impl } @Override - public final void formatXML(Writer writer, XMLFormat format) { - if (format == null) - format = XMLFormat.DEFAULT_FOR_RESULTS; + final XMLFormat defaultXMLFormat() { + return XMLFormat.DEFAULT_FOR_RESULTS; + } + @Override + public final void formatXML(Writer writer, XMLFormat format) { String newline = format.newline(); int recordLevel = format.header() ? 2 : 1; @@ -1289,9 +1298,11 @@ abstract class AbstractResult extends AbstractFormattable impl eValue.setAttribute("field", field.getName()); eRecord.appendChild(eValue); - if (value != null) { - eValue.setTextContent(format0(value, false, false)); - } + if (value != null) + if (value instanceof XML && !format.quoteNested()) + eValue.appendChild(createContent(builder, document, ((XML) value).data())); + else + eValue.setTextContent(format0(value, false, false)); } } @@ -1302,6 +1313,61 @@ abstract class AbstractResult extends AbstractFormattable impl } } + // Taken from JOOX Util.createContent() + static final DocumentFragment createContent(DocumentBuilder builder, Document doc, String text) { + + // [#150] Text might hold XML content, which can be leniently identified by the presence + // of either < or & characters (other entities, like >, ", ' are not stricly XML content) + if (text != null && (text.contains("<") || text.contains("&"))) { + + // [#162] Prevent log output + builder.setErrorHandler(new DefaultHandler()); + + try { + + // [#128] Trimming will get rid of leading and trailing whitespace, which would + // otherwise cause a HIERARCHY_REQUEST_ERR raised by the parser + text = text.trim(); + + // There is a processing instruction. We can safely assume + // valid XML and parse it as such + if (text.startsWith("" + text + ""; + Document parsed = builder.parse(new InputSource(new StringReader(wrapped))); + DocumentFragment fragment = parsed.createDocumentFragment(); + NodeList children = parsed.getDocumentElement().getChildNodes(); + + // appendChild removes children also from NodeList! + while (children.getLength() > 0) { + fragment.appendChild(children.item(0)); + } + + return (DocumentFragment) doc.importNode(fragment, true); + } + } + + // This does not occur + catch (java.io.IOException ignore) {} + + // The XML content is invalid + catch (SAXException ignore) {} + } + + // Plain text or invalid XML + return null; + } + + @Override public final H intoXML(H handler, XMLFormat format) throws SAXException { Attributes empty = new AttributesImpl(); diff --git a/jOOQ/src/main/java/org/jooq/impl/ArrayRecordImpl.java b/jOOQ/src/main/java/org/jooq/impl/ArrayRecordImpl.java index 46b41f0b71..48d0d7219e 100644 --- a/jOOQ/src/main/java/org/jooq/impl/ArrayRecordImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/ArrayRecordImpl.java @@ -412,6 +412,16 @@ package org.jooq.impl; + + + + + + + + + + diff --git a/jOOQ/src/main/java/org/jooq/impl/XMLElement.java b/jOOQ/src/main/java/org/jooq/impl/XMLElement.java index c981fd46f8..f39924fe86 100644 --- a/jOOQ/src/main/java/org/jooq/impl/XMLElement.java +++ b/jOOQ/src/main/java/org/jooq/impl/XMLElement.java @@ -65,7 +65,7 @@ final class XMLElement extends AbstractField { private final QueryPartList> content; XMLElement(Name elementName, XMLAttributes attributes, Collection> content) { - super(N_XMLCONCAT, SQLDataType.XML); + super(N_XMLELEMENT, SQLDataType.XML); this.elementName = elementName; this.attributes = attributes;