private String parseCharacterReference(String entity) throws XPathException {
        int value = 0;
        if (entity.charAt(1) == 'x') {
            if (entity.length() < 3) {
                grumble("No hex digits in hexadecimal character reference");
            }
            entity = entity.toLowerCase();
            for (int i = 2; i < entity.length(); i++) {
                int digit = "0123456789abcdef".indexOf(entity.charAt(i));
                if (digit < 0) {
                    grumble("Invalid hex digit '" + entity.charAt(i) + "' in character reference");
                }
                value = (value * 16) + digit;
                if (value > UTF16CharacterSet.NONBMP_MAX) {
                    grumble("Character reference exceeds Unicode codepoint limit", "XQST0090");
                }
            }
        } else {
            for (int i = 1; i < entity.length(); i++) {
                int digit = "0123456789".indexOf(entity.charAt(i));
                if (digit < 0) {
                    grumble("Invalid digit '" + entity.charAt(i) + "' in decimal character reference");
                }
                value = (value * 10) + digit;
                if (value > UTF16CharacterSet.NONBMP_MAX) {
                    grumble("Character reference exceeds Unicode codepoint limit", "XQST0090");
                }
            }
        }

        NameChecker nc = env.getConfiguration().getNameChecker();
        if (!nc.isValidChar(value)) {
            grumble("Invalid XML character reference x"
                    + Integer.toHexString(value), "XQST0090");
        }
        // following code borrowed from AElfred
        // Check for surrogates: 00000000 0000xxxx yyyyyyyy zzzzzzzz
        //  (1101|10xx|xxyy|yyyy + 1101|11yy|zzzz|zzzz:
        if (value <= 0x0000ffff) {
            // no surrogates needed
            return "" + (char)value;
        } else if (value <= 0x0010ffff) {
            value -= 0x10000;
            // > 16 bits, surrogate needed
            return "" + ((char)(0xd800 | (value >> 10)))
                    + ((char)(0xdc00 | (value & 0x0003ff)));
        } else {
            // too big for surrogate
            grumble("Character reference x" + Integer.toHexString(value) + " is too large", "XQST0090");
        }
        return null;
    }