Skip to main content

@Xml Whitespace Handling

The XmlFormat.MIXED, XmlFormat.MIXED_PWS, XmlFormat.TEXT, and XmlFormat.TEXT_PWS formats all serialize values directly as element content, which raises the question of how empty strings and leading/trailing whitespace survive a round trip. This page collects the whitespace rules that apply to those formats.

Whitespace (tabs and newlines) are not added to MIXED child nodes in readable-output mode. This helps ensures strings in the serialized output can be losslessly parsed back into their original forms when they contain whitespace characters. If the XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES setting was not useless in Java, we could support lossless readable XML for MIXED content. But as of Java 8, it still does not work. XML suffers from other deficiencies as well that affect MIXED content. For example, <X/> and <X></X> are equivalent in XML and indistinguishable by the Java XML parsers. This makes it impossible to differentiate between an empty element and an element containing an empty string. This causes empty strings to get lost in translation. To alleviate this, we use the constructs "xE000" to represent an empty string, and "x0020" to represent leading and trailing spaces. The examples below show how whitespace is handled under various circumstances:

Data typeXML
@Marshalled(typeName="X")
class MyBean {
@Xml(format=XmlFormat.TEXT)
public String a = null;
}
<X/>
@Marshalled(typeName="X")
class MyBean {
@Xml(format=XmlFormat.TEXT)
public String a = "";
}
<X>_xE000_</X>
@Marshalled(typeName="X")
class MyBean {
@Xml(format=XmlFormat.TEXT)
public String a = " ";
}
<X>_x0020_</X>
@Marshalled(typeName="X")
class MyBean {
@Xml(format=XmlFormat.TEXT)
public String a = " ";
}
<X>_x0020__x0020_</X>
@Marshalled(typeName="X")
class MyBean {
@Xml(format=XmlFormat.TEXT)
public String a = " foobar ";
}
<X>_x0020_ foobar _x0020_</X>
@Marshalled(typeName="X")
class MyBean {
@Xml(format=XmlFormat.TEXT_PWS)
public String a = null;
}
<X/>
@Marshalled(typeName="X")
class MyBean {
@Xml(format=XmlFormat.TEXT_PWS)
public String a = "";
}
<X>_xE000_</X>
@Marshalled(typeName="X")
class MyBean {
@Xml(format=XmlFormat.TEXT_PWS)
public String a = " ";
}
<X> </X>
@Marshalled(typeName="X")
class MyBean {
@Xml(format=XmlFormat.TEXT_PWS)
public String a = " ";
}
<X>  </X>
@Marshalled(typeName="X")
class MyBean {
@Xml(format=XmlFormat.TEXT_PWS)
public String a = " foobar ";
}
<X>  foobar  </X>
@Marshalled(typeName="X")
class MyBean {
@Xml(format=XmlFormat.MIXED)
public String[] a = null;
}
<X/>
@Marshalled(typeName="X")
class MyBean {
@Xml(format=XmlFormat.MIXED)
public String[] a = {""};
}
<X>_xE000_</X>
@Marshalled(typeName="X")
class MyBean {
@Xml(format=XmlFormat.MIXED)
public String[] a = {" "};
}
<X>_x0020_</X>
@Marshalled(typeName="X")
class MyBean {
@Xml(format=XmlFormat.MIXED)
public String[] a = {" "};
}
<X>_x0020__x0020_</X>
@Marshalled(typeName="X")
class MyBean {
@Xml(format=XmlFormat.MIXED)
public String[] a = {" foobar "};
}
<X>_x0020_ foobar _x0020_</X>
@Marshalled(typeName="X")
class MyBean {
@Xml(format=XmlFormat.MIXED_PWS)
public String[] a = null;
}
<X/>
@Marshalled(typeName="X")
class MyBean {
@Xml(format=XmlFormat.MIXED_PWS)
public String[] a = {""};
}
<X>_xE000_</X>
@Marshalled(typeName="X")
class MyBean {
@Xml(format=XmlFormat.MIXED_PWS)
public String[] a = {" "};
}
<X> </X>
@Marshalled(typeName="X")
class MyBean {
@Xml(format=XmlFormat.MIXED_PWS)
public String[] a = {" "};
}
<X>  </X>
@Marshalled(typeName="X")
class MyBean {
@Xml(format=XmlFormat.MIXED_PWS)
public String[] a = {" foobar "};
}
<X>  foobar  </X>

See also​