Zara was working on an Android app. One fine morning, her client messaged her with a request - “Please replace the existing TOS with this new content”. The new content was pasted into the email directly. The client thought it would be a quick job. It was, in fact, a relatively quick job, but sometimes these things can be more complicated than you’d expect, at first.

“Easy-peasy”, thought Zara.

In the existing TOS, each paragraph of text was displayed in a TextView. You could argue that the entire TOS could be copied as text content into a single TextView within a ScrollView. Content could be broken into paragraphs using multiple line separators. Ssomething like that might actually be simpler to maintain than paragraphs displayed in multiple TextViews. However, there were images mixed in, and perhaps multiple TextViews worked better in this situation.

She started to add each paragraph to strings.xml, replacing existing paragraphs, and soon noticed a problem. The content that had been sent to her contained a mix of UTF-8 and ASCII double and single quotes.

Now she had a problem.

The client wanted something done. He was a busy guy. He was nice, friendly, and patient, but she was pretty sure he wouldn’t enjoy an email discussion asking whether he really wanted UTF-8 quotes, or did he perhaps really want ASCII quotes, or maybe he genuinely wanted the mix of ASCII and UTF-8 that she’d been sent?

So, she decided that she’d switch all quotes and apostrophes to ASCII. If someone noticed this later, and wanted a change to a fancier UTF-8 quote, she wanted to make it easy to implement a change request. She decided to add an ENTITY to the strings.xml file with the TOS content. That entity would be used like a variable throughout the text. Like so:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE resources [
    <!ENTITY bullet "&#8226;" >
    <!ENTITY apo "'">
    <!ENTITY quo """>
]>
<resources>
    <string name="tos_header">TOS</string>
    <string name="tos_p1">Our general goal is &quo;don&apo;t be evil&quo;</string>
    <string name="tos_p1">&bullet; Reason number 1...</string>
    ...
</resources>

The triple quotes in the quo variable were worrisome, but the parser didn’t complain. Great! From now on, it would be easy to just change the entity, and not have to make changes to text using “bulk search and replace”. That is easy, too, but she thought her ENTITY approach would make the intent more clear, and bulk replace can sometimes lead to bugs…

She built the app, and the build failed with an error:

The declaration for the entity "quo" must end with '>'.

Not the most helpful error message, but clearly the parser didn’t love her triple quotes. After some experimentation, she found a working solution:

    <!ENTITY apo "\'">
    <!ENTITY quo '\"'>

The build now completed successfully, and the TOS screen looked correct. The only problem now was that these new entities broke some functionality in the IDE. Android Studio’s “Problems” tab indicated that the strings.xml file was incorrect, and the design view of the TOS screen was broken! There were two problems listed:

Unexpected end of file
Valid XML document must have a root tag

She experimented a bit to get rid of these problems… it turned out that if she duplicated the “quo” entity, the problem went away! Like this:

    <!ENTITY apo "\'">
    <!ENTITY quo '\"'>
    <!ENTITY quo '\"'>

That just didn’t seem right, though, making a change to keep an IDE happy. She wound up ignoring the “Problems” and finished up the TOS work just before her coffee break. Sometimes, even the simplest tasks can wind up taking more time than one expects in software development!