[jOOQ/jOOQ#13873] Support <element/> array also for Result::intoXML

This includes:

- [jOOQ/jOOQ#19160] NullPointerException in Result::intoXML when working
with XML fields whose content is a text node
- [jOOQ/jOOQ#19158] Result::intoXML does not recurse into nested
Formattables
This commit is contained in:
Lukas Eder 2025-10-07 12:05:22 +02:00
parent 2090e23f22
commit 3cb53b66aa

View File

@ -108,6 +108,7 @@ 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.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
@ -890,12 +891,12 @@ abstract class AbstractResult<R extends Record> extends AbstractFormattable impl
for (int index = 0; index < size; index++) {
Object value = record.get(index);
writer.append(newline).append(format.indentString(recordLevel + 1));
String tag = format.recordFormat() == COLUMN_NAME_ELEMENTS
? escapeXML(fields.field(index).getName())
: "value";
if (value != null || format.nullFormat() != ABSENT_ELEMENT) {
writer.append(newline).append(format.indentString(recordLevel + 1));
String tag = format.recordFormat() == COLUMN_NAME_ELEMENTS
? escapeXML(fields.field(index).getName())
: "value";
writer.append("<" + tag);
if (format.recordFormat() == VALUE_ELEMENTS_WITH_FIELD_ATTRIBUTE) {
writer.append(" field=\"");
@ -920,7 +921,7 @@ abstract class AbstractResult<R extends Record> extends AbstractFormattable impl
writer.append(newline).append(format.indentString(recordLevel)).append("</record>");
}
private static void formatXMLContent(
private final static void formatXMLContent(
Writer writer,
XMLFormat format,
int recordLevel,
@ -1234,6 +1235,10 @@ abstract class AbstractResult<R extends Record> extends AbstractFormattable impl
if (format.xmlns())
eResult.setAttribute("xmlns", Constants.NS_EXPORT);
if (format.nullFormat() == XSI_NIL)
eResult.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
document.appendChild(eResult);
Element eRecordParent = eResult;
@ -1281,21 +1286,19 @@ abstract class AbstractResult<R extends Record> extends AbstractFormattable impl
Field<?> field = fields.field(index);
Object value = record.get(index);
String tag = format.recordFormat() == COLUMN_NAME_ELEMENTS
? escapeXML(fields.field(index).getName())
: "value";
if (value != null || format.nullFormat() != ABSENT_ELEMENT) {
String tag = format.recordFormat() == COLUMN_NAME_ELEMENTS
? escapeXML(field.getName())
: "value";
Element eValue = document.createElement(tag);
Element eValue = document.createElement(tag);
if (format.recordFormat() == VALUE_ELEMENTS_WITH_FIELD_ATTRIBUTE)
eValue.setAttribute("field", field.getName());
eRecord.appendChild(eValue);
if (format.recordFormat() == VALUE_ELEMENTS_WITH_FIELD_ATTRIBUTE)
eValue.setAttribute("field", field.getName());
eRecord.appendChild(eValue);
if (value != null)
if (value instanceof XML && !format.quoteNested())
eValue.appendChild(createContent(builder, document, ((XML) value).data()));
else
eValue.setTextContent(format0(value, false, false));
intoXMLContent(format, builder, document, value, eValue);
}
}
}
@ -1306,6 +1309,67 @@ abstract class AbstractResult<R extends Record> extends AbstractFormattable impl
}
}
private final void intoXMLContent(
XMLFormat format,
DocumentBuilder builder,
Document document,
Object value,
Element eParent
) {
if (value == null) {
if (format.nullFormat() == XSI_NIL)
eParent.setAttribute("xsi:nil", "true");
}
else if (value instanceof Formattable f) {
Document d = f.intoXML(format);
Node n = document.importNode(d.getDocumentElement(), true);
// [#19158] [#19159] intoXML() wraps a <record/> in an unnecessary <result/>
if (value instanceof Record)
n = childElement(n);
eParent.appendChild(n);
}
else if (format.arrayFormat() == ArrayFormat.ELEMENTS && value instanceof Object[] a) {
for (Object o : a) {
if (o != null || format.nullFormat() != ABSENT_ELEMENT) {
Element eElement = document.createElement("element");
eParent.appendChild(eElement);
if (o == null) {
if (format.nullFormat() == XSI_NIL)
eElement.setAttribute("xsi:nil", "true");
}
else
intoXMLContent(format, builder, document, o, eElement);
}
}
}
else if (value instanceof XML && !format.quoteNested()) {
DocumentFragment content = createContent(builder, document, ((XML) value).data());
if (content != null)
eParent.appendChild(content);
else
eParent.setTextContent(((XML) value).data());
}
else
eParent.setTextContent(format0(value, false, false));
}
private final Node childElement(Node n) {
NodeList l = n.getChildNodes();
for (int i = 0; i < l.getLength(); i++) {
Node e = l.item(i);
if (e.getNodeType() == Node.ELEMENT_NODE)
return e;
}
return n;
}
// Taken from JOOX Util.createContent()
static final DocumentFragment createContent(DocumentBuilder builder, Document doc, String text) {