Java - Как проверить, является ли строка допустимым именем XML-элемента?

знаете ли вы функцию в java, которая будет проверять правильность имени строки XML.

Форма w3schools:

Элементы XML должны следовать этим наименованиям правила:

  • Имена могут содержать буквы, цифры и другие символы
  • Имена не могут начинаться с цифры или символа пунктуации
  • Имена не могут начинаться с букв xml (или XML, или Xml и т.д.)
  • Имена не могут содержать пробелы

Я нашел другие вопросы, предлагающие регулярные решения, нет ли функции, которая уже делает это?

Ответ 1

Если вы используете синтаксический анализатор XML Xerces, вы можете использовать класс XMLChar (или XML11Char) isValidName(), например:

org.apache.xerces.util.XMLChar.isValidName(String name)

Здесь также есть пример кода для isValidName.

Ответ 2

Соответствующая продукция из спецификации http://www.w3.org/TR/xml/#NT-Name

Имя:: == NameStartChar NameChar *

NameStartChar:: = ":" | [A-Z] | "_" | [a-z] | [# xC0- # xD6] | [# xD8- # xF6] | [# xF8- # x2FF] | [# x370- # x37D] | [# x37F- # x1FFF] | [# x200C- # x200D] | [# x2070- # x218F] | [# x2C00- # x2FEF] | [# x3001- # xD7FF] | [# xF900- # xFDCF] | [# xFDF0- # xFFFD] | [# X10000- # xEFFFF]

NameChar:: = NameStartChar | "-" | "" | [0-9] | # xB7 | [# x0300- # x036F] | [# X203F- # x2040]

Итак, регулярное выражение соответствует ему

"^[:A-Z_a-z\\u00C0\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02ff\\u0370-\\u037d"
+ "\\u037f-\\u1fff\\u200c\\u200d\\u2070-\\u218f\\u2c00-\\u2fef\\u3001-\\ud7ff"
+ "\\uf900-\\ufdcf\\ufdf0-\\ufffd\\x10000-\\xEFFFF]"
+ "[:A-Z_a-z\\u00C0\\u00D6\\u00D8-\\u00F6"
+ "\\u00F8-\\u02ff\\u0370-\\u037d\\u037f-\\u1fff\\u200c\\u200d\\u2070-\\u218f"
+ "\\u2c00-\\u2fef\\u3001-\\udfff\\uf900-\\ufdcf\\ufdf0-\\ufffd\\-\\.0-9"
+ "\\u00b7\\u0300-\\u036f\\u203f-\\u2040]*\\Z"

Если вы хотите иметь дело с именами с именами, вам нужно убедиться, что существует не более одного двоеточия, поэтому

"^[A-Z_a-z\\u00C0\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02ff\\u0370-\\u037d"
+ "\\u037f-\\u1fff\\u200c\\u200d\\u2070-\\u218f\\u2c00-\\u2fef\\u3001-\\udfff"
+ "\\uf900-\\ufdcf\\ufdf0-\\ufffd]"
+ "[A-Z_a-z\\u00C0\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02ff\\u0370-\\u037d"
+ "\\u037f-\\u1fff\\u200c\\u200d\\u2070-\\u218f\\u2c00-\\u2fef\\u3001-\\udfff"
+ "\\uf900-\\ufdcf\\ufdf0-\\ufffd\\-\\.0-9\\u00b7\\u0300-\\u036f\\u203f-\\u2040]*"
+ "(?::[A-Z_a-z\\u00C0\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02ff\\u0370-\\u037d"
+ "\\u037f-\\u1fff\\u200c\\u200d\\u2070-\\u218f\\u2c00-\\u2fef\\u3001-\\udfff"
+ "\\uf900-\\ufdcf\\ufdf0-\\ufffd]"
+ "[A-Z_a-z\\u00C0\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02ff\\u0370-\\u037d"
+ "\\u037f-\\u1fff\\u200c\\u200d\\u2070-\\u218f\\u2c00-\\u2fef\\u3001-\\udfff"
+ "\\uf900-\\ufdcf\\ufdf0-\\ufffd\\-\\.0-9\\u00b7\\u0300-\\u036f\\u203f-\\u2040]*)?\\Z"

(пропустил еще один 03gf, изменил оба на 036f)

Ответ 3

Как текущее дополнение к принятый ответ:

По крайней мере, Oracle JDK 1.8 (вероятно, более старые) также использует парсер Xerces внутри непубличных пакетов com.sun.*. Вы никогда не должны напрямую использовать какие-либо реализации из этих классов, поскольку они могут измениться без дальнейшего уведомления в будущих версиях JDK! Однако требуемый код для проверки действительности имени элемента xml очень хорошо инкапсулирован и может быть скопирован в ваш собственный код. Таким образом, вы можете избежать другой зависимости от внешней библиотеки.

Это необходимый код, взятый из внутреннего класса com.sun.org.apache.xerces.internal.util.XMLChar:

public class XMLChar {

    /** Character flags. */
    private static final byte[] CHARS = new byte[1 << 16];

    /** Name start character mask. */
    public static final int MASK_NAME_START = 0x04;

    /** Name character mask. */
    public static final int MASK_NAME = 0x08;

    static {
        // Initializing the Character Flag Array
        // Code generated by: XMLCharGenerator.

        CHARS[9] = 35;
        CHARS[10] = 19;
        CHARS[13] = 19;

        // ...
        // the entire static block must be copied
    }

    /**
     * Check to see if a string is a valid Name according to [5]
     * in the XML 1.0 Recommendation
     *
     * @param name string to check
     * @return true if name is a valid Name
     */
    public static boolean isValidName(String name) {
        final int length = name.length();
        if (length == 0) {
            return false;
        }
        char ch = name.charAt(0);
        if (!isNameStart(ch)) {
            return false;
        }
        for (int i = 1; i < length; ++i) {
            ch = name.charAt(i);
            if (!isName(ch)) {
                return false;
            }
        }
        return true;
    }

    /**
     * Returns true if the specified character is a valid name start
     * character as defined by production [5] in the XML 1.0
     * specification.
     *
     * @param c The character to check.
     */
    public static boolean isNameStart(int c) {
        return c < 0x10000 && (CHARS[c] & MASK_NAME_START) != 0;
    }

    /**
     * Returns true if the specified character is a valid name
     * character as defined by production [4] in the XML 1.0
     * specification.
     *
     * @param c The character to check.
     */
    public static boolean isName(int c) {
        return c < 0x10000 && (CHARS[c] & MASK_NAME) != 0;
    }
}

Ответ 4

Использование утилит org.apache.xerces - хороший способ; однако, если вам нужно придерживаться кода Java, который является частью стандартного API Java, тогда следующий код будет делать это:

public void parse(String xml) throws Exception {

    XMLReader parser = XMLReaderFactory.createXMLReader();
    parser.setContentHandler(new DefaultHandler());
    InputSource source = new InputSource(new ByteArrayInputStream(xml.getBytes()));
    parser.parse(source);
}