   case "quot": entityValue = '\"'; break;
                case "apos": entityValue = '\''; break;
                default:
                    if( entityName[0] is 'x' ){
                        if( semi < 2 ) error();
                        if( semi > 9 ) error();
                        foreach( hex; entityName[1..$] ){
                            entityValue <<= 4;
                            if( hex >= '0' && hex <= '9' ){
                                entityValue |= ( hex - '0' );
                            }
                            else if( hex >= 'a' && hex <= 'f' ){
                                entityValue |= ( hex - 'a' );
                            }
                            else if( hex >= 'A' && hex <= 'F' ){
                                entityValue |= ( hex - 'A' );
                            }
                            else{
                                error();
                            }
                        }
                    }
                    else{
                        if( semi < 1 ) error();
                        if( semi > 9 ) error();
                        foreach( dec; entityName[1..$] ){
                            if( dec >= '0' && dec <= '9' ){
                                entityValue *= 10;
                                entityValue += ( dec - '0' );
                            }
                            else{
                                error();
                            }
                        }
                    }
            }
            String res = String_valueOf( entityValue );
            trg = trg[ res.length .. $ ];
            src = src[ semi +1 .. $ ]; // go past semi
        }
    }
    return str[ 0 .. trg.ptr-str.ptr ];
}


/++
 + Encode XML entities into UTF8 string.
 + First checks if processing is needed.
 + If not, the original string is returned.
 + If processing is needed, a new string is allocated.
 +/
String xmlEscape( String xml ){
    bool needsReplacement( dchar c ){
        switch( c ){
            c