#748 - close XML tag explicitly for empty tags with configuration.

This commit is contained in:
rudrajyoti biswas 2023-10-25 23:23:00 +05:30
parent 1a2108efa2
commit c6ec2f0e4c
4 changed files with 70 additions and 8 deletions

View File

@ -877,6 +877,18 @@ public class XML {
} }
} }
} else if ("".equals(value)) { } else if ("".equals(value)) {
if (config.isCloseEmptyTag()){
sb.append(indent(indent));
sb.append('<');
sb.append(key);
sb.append(">");
sb.append("</");
sb.append(key);
sb.append(">");
if (indentFactor > 0) {
sb.append("\n");
}
}else {
sb.append(indent(indent)); sb.append(indent(indent));
sb.append('<'); sb.append('<');
sb.append(key); sb.append(key);
@ -884,6 +896,7 @@ public class XML {
if (indentFactor > 0) { if (indentFactor > 0) {
sb.append("\n"); sb.append("\n");
} }
}
// Emit a new tag <k> // Emit a new tag <k>

View File

@ -43,6 +43,13 @@ public class XMLParserConfiguration extends ParserConfiguration {
*/ */
private boolean convertNilAttributeToNull; private boolean convertNilAttributeToNull;
/**
* When creating an XML from JSON Object, an empty tag by default will self-close.
* If it has to be closed explicitly, with empty content between start and end tag,
* this flag is to be turned on.
*/
private boolean closeEmptyTag;
/** /**
* This will allow type conversion for values in XML if xsi:type attribute is defined * This will allow type conversion for values in XML if xsi:type attribute is defined
*/ */
@ -145,12 +152,13 @@ public class XMLParserConfiguration extends ParserConfiguration {
*/ */
private XMLParserConfiguration (final boolean keepStrings, final String cDataTagName, private XMLParserConfiguration (final boolean keepStrings, final String cDataTagName,
final boolean convertNilAttributeToNull, final Map<String, XMLXsiTypeConverter<?>> xsiTypeMap, final Set<String> forceList, final boolean convertNilAttributeToNull, final Map<String, XMLXsiTypeConverter<?>> xsiTypeMap, final Set<String> forceList,
final int maxNestingDepth) { final int maxNestingDepth, final boolean closeEmptyTag) {
super(keepStrings, maxNestingDepth); super(keepStrings, maxNestingDepth);
this.cDataTagName = cDataTagName; this.cDataTagName = cDataTagName;
this.convertNilAttributeToNull = convertNilAttributeToNull; this.convertNilAttributeToNull = convertNilAttributeToNull;
this.xsiTypeMap = Collections.unmodifiableMap(xsiTypeMap); this.xsiTypeMap = Collections.unmodifiableMap(xsiTypeMap);
this.forceList = Collections.unmodifiableSet(forceList); this.forceList = Collections.unmodifiableSet(forceList);
this.closeEmptyTag = closeEmptyTag;
} }
/** /**
@ -169,7 +177,8 @@ public class XMLParserConfiguration extends ParserConfiguration {
this.convertNilAttributeToNull, this.convertNilAttributeToNull,
this.xsiTypeMap, this.xsiTypeMap,
this.forceList, this.forceList,
this.maxNestingDepth this.maxNestingDepth,
this.closeEmptyTag
); );
} }
@ -303,4 +312,13 @@ public class XMLParserConfiguration extends ParserConfiguration {
public XMLParserConfiguration withMaxNestingDepth(int maxNestingDepth) { public XMLParserConfiguration withMaxNestingDepth(int maxNestingDepth) {
return super.withMaxNestingDepth(maxNestingDepth); return super.withMaxNestingDepth(maxNestingDepth);
} }
public XMLParserConfiguration withCloseEmptyTag(boolean closeEmptyTag){
this.closeEmptyTag = closeEmptyTag;
return this;
}
public boolean isCloseEmptyTag() {
return this.closeEmptyTag;
}
} }

View File

@ -557,6 +557,17 @@ public class XMLConfigurationTest {
assertEquals(actualXML, resultXML); assertEquals(actualXML, resultXML);
} }
@Test
public void shouldHandleEmptyNodeValue()
{
JSONObject inputJSON = new JSONObject();
inputJSON.put("Emptyness", "");
String expectedXmlWithoutExplicitEndTag = "<Emptyness/>";
String expectedXmlWithExplicitEndTag = "<Emptyness></Emptyness>";
assertEquals(expectedXmlWithoutExplicitEndTag, XML.toString(inputJSON, null, new XMLParserConfiguration().withCloseEmptyTag(false)));
assertEquals(expectedXmlWithExplicitEndTag, XML.toString(inputJSON, null, new XMLParserConfiguration().withCloseEmptyTag(true)));
}
/** /**
* Investigate exactly how the "content" keyword works * Investigate exactly how the "content" keyword works
*/ */

View File

@ -1177,6 +1177,26 @@ public class XMLTest {
} }
@Test
public void shouldCreateExplicitEndTagWithEmptyValueWhenConfigured(){
String jsonString = "{outer:{innerOne:\"\", innerTwo:\"two\"}}";
JSONObject jsonObject = new JSONObject(jsonString);
String expectedXmlString = "<encloser><outer><innerOne></innerOne><innerTwo>two</innerTwo></outer></encloser>";
String xmlForm = XML.toString(jsonObject,"encloser", new XMLParserConfiguration().withCloseEmptyTag(true));
assertEquals(expectedXmlString, xmlForm);
}
@Test
public void shouldNotCreateExplicitEndTagWithEmptyValueWhenNotConfigured(){
String jsonString = "{outer:{innerOne:\"\", innerTwo:\"two\"}}";
JSONObject jsonObject = new JSONObject(jsonString);
String expectedXmlString = "<encloser><outer><innerOne/><innerTwo>two</innerTwo></outer></encloser>";
String xmlForm = XML.toString(jsonObject,"encloser", new XMLParserConfiguration().withCloseEmptyTag(false));
assertEquals(expectedXmlString, xmlForm);
}
@Test @Test
public void testIndentSimpleJsonObject(){ public void testIndentSimpleJsonObject(){
String str = "{ \"employee\": { \n" + String str = "{ \"employee\": { \n" +