提交 1e9a21cf authored 作者: Thomas Mueller's avatar Thomas Mueller

XMLTEXT now supports an optional parameter to escape newlines. XMLNODE now…

XMLTEXT now supports an optional parameter to escape newlines. XMLNODE now support an optional parameter to disable indentation.
上级 49d9d2ef
......@@ -3108,9 +3108,12 @@ CALL XMLNODE('a', XMLATTR('href', 'http://h2database.com'))
"
"Functions (String)","XMLNODE","
XMLNODE(elementString [, attributesString [, contentString]])
XMLNODE(elementString [, attributesString [, contentString [, indentBoolean]])
","
Create an XML node element.
An empty or null attribute string means no attributes are set.
An empty or null content string means the node is empty.
The content is indented by default if it contains a newline.
This method returns a string.
","
CALL XMLNODE('a', XMLATTR('href', 'http://h2database.com'), 'H2')
......@@ -3139,15 +3142,17 @@ CALL XMLCDATA('data')
"Functions (String)","XMLSTARTDOC","
XMLSTARTDOC()
","
The string ""<?xml version='1.0'?>"" is returned.
Returns the XML decrations.
The result is always ""<?xml version=""1.0""?>"".
","
CALL XMLSTARTDOC()
"
"Functions (String)","XMLTEXT","
XMLTEXT(valueString)
XMLTEXT(valueString [, escapeNewlineBoolean])
","
Creates an XML text element.
If enabled, newlines and linefeeds are converted to XML entities (&#).
This method returns a string.
","
CALL XMLTEXT('test')
......
......@@ -254,7 +254,7 @@ public class Function extends Expression implements FunctionCall {
addFunction("XMLCOMMENT", XMLCOMMENT, 1, Value.STRING);
addFunction("XMLCDATA", XMLCDATA, 1, Value.STRING);
addFunction("XMLSTARTDOC", XMLSTARTDOC, 0, Value.STRING);
addFunction("XMLTEXT", XMLTEXT, 1, Value.STRING);
addFunction("XMLTEXT", XMLTEXT, VAR_ARGS, Value.STRING);
addFunction("REGEXP_REPLACE", REGEXP_REPLACE, 3, Value.STRING);
addFunction("RPAD", RPAD, VAR_ARGS, Value.STRING);
addFunction("LPAD", LPAD, VAR_ARGS, Value.STRING);
......@@ -634,9 +634,6 @@ public class Function extends Expression implements FunctionCall {
case XMLSTARTDOC:
result = ValueString.get(StringUtils.xmlStartDoc());
break;
case XMLTEXT:
result = ValueString.get(StringUtils.xmlText(v0.getString()));
break;
case DAY_NAME: {
SimpleDateFormat dayName = new SimpleDateFormat("EEEE", Locale.ENGLISH);
result = ValueString.get(dayName.format(v0.getDate()));
......@@ -1042,7 +1039,8 @@ public class Function extends Expression implements FunctionCall {
case XMLNODE: {
String attr = v1 == null ? null : v1 == ValueNull.INSTANCE ? null : v1.getString();
String content = v2 == null ? null : v2 == ValueNull.INSTANCE ? null : v2.getString();
result = ValueString.get(StringUtils.xmlNode(v0.getString(), attr, content));
boolean indent = v3 == null ? true : v3.getBoolean();
result = ValueString.get(StringUtils.xmlNode(v0.getString(), attr, content, indent));
break;
}
case REGEXP_REPLACE: {
......@@ -1207,6 +1205,13 @@ public class Function extends Expression implements FunctionCall {
result = v0.convertPrecision(v1.getLong(), v2.getBoolean());
break;
}
case XMLTEXT:
if (v1 == null) {
result = ValueString.get(StringUtils.xmlText(v0.getString()));
} else {
result = ValueString.get(StringUtils.xmlText(v0.getString(), v1.getBoolean()));
}
break;
default:
throw DbException.throwInternalError("type=" + info.type);
}
......@@ -1620,6 +1625,7 @@ public class Function extends Expression implements FunctionCall {
case TRIM:
case FILE_READ:
case ROUND:
case XMLTEXT:
min = 1;
max = 2;
break;
......@@ -1640,7 +1646,7 @@ public class Function extends Expression implements FunctionCall {
break;
case XMLNODE:
min = 1;
max = 3;
max = 4;
break;
case FORMATDATETIME:
case PARSEDATETIME:
......
......@@ -571,11 +571,26 @@ public class StringUtils {
* @return the node
*/
public static String xmlNode(String name, String attributes, String content) {
return xmlNode(name, attributes, content, true);
}
/**
* Create an XML node with optional attributes and content. The data is
* indented with 4 spaces if it contains a newline character and the indent
* parameter is set to true.
*
* @param name the element name
* @param attributes the attributes (may be null)
* @param content the content (may be null)
* @param indent whether to indent the content if it contains a newline
* @return the node
*/
public static String xmlNode(String name, String attributes, String content, boolean indent) {
String start = attributes == null ? name : name + attributes;
if (content == null) {
return "<" + start + "/>\n";
}
if (content.indexOf('\n') >= 0) {
if (indent && content.indexOf('\n') >= 0) {
content = "\n" + indent(content);
}
return "<" + start + ">" + content + "</" + name + ">\n";
......@@ -672,6 +687,17 @@ public class StringUtils {
* @return the escaped text
*/
public static String xmlText(String text) {
return xmlText(text, false);
}
/**
* Escapes an XML text element.
*
* @param text the text data
* @param escapeNewline whether to escape newlines
* @return the escaped text
*/
public static String xmlText(String text, boolean escapeNewline) {
int length = text.length();
StringBuilder buff = new StringBuilder(length);
for (int i = 0; i < length; i++) {
......@@ -694,6 +720,14 @@ public class StringUtils {
break;
case '\r':
case '\n':
if (escapeNewline) {
buff.append("&#x").
append(Integer.toHexString(ch)).
append(';');
} else {
buff.append(ch);
}
break;
case '\t':
buff.append(ch);
break;
......
......@@ -8916,6 +8916,18 @@ CALL XMLNODE('p', null, 'Hello World');
> <p>Hello World</p>
> rows: 1
SELECT XMLNODE('p', null, 'Hello' || chr(10) || 'World') X;
> X
> ---------------------
> <p> Hello World </p>
> rows: 1
SELECT XMLNODE('p', null, 'Hello' || chr(10) || 'World', false) X;
> X
> -------------------
> <p>Hello World</p>
> rows: 1
CALL XMLCOMMENT('Test');
> STRINGDECODE('<!-- Test -->\n')
> -------------------------------
......@@ -8958,6 +8970,18 @@ CALL XMLTEXT('<test>');
> &lt;test&gt;
> rows: 1
CALL XMLTEXT('hello' || chr(10) || 'world');
> STRINGDECODE('hello\nworld')
> ----------------------------
> hello world
> rows: 1
CALL XMLTEXT('hello' || chr(10) || 'world', true);
> 'hello&#xa;world'
> -----------------
> hello&#xa;world
> rows: 1
create memory table test(id int primary key, name varchar(255));
> ok
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论