Недопустимые символы в имени тега XML - PullRequest
0 голосов
/ 31 января 2020

У нас есть огромная база данных, где пользователи могут создавать настраиваемые поля. Каждый символ UTF-8 допускается в своем имени. До нескольких недель go, когда они экспортировали свои данные в XML, только недопустимые символы, которые были у пользователей в их таблицах, были sla sh / и пробелами , и мы заменяли их символами подчеркивания.

Теперь я вижу, что некоторые пользователи, которым нужен экспорт в XML, используют в именах своих полей *, ! ... Так что если вместо имени их поля valid_name указано, например, invalid*name!, этот скрипт сломается.

Часть кода, используемая для определения имени тега:

$doc = new DOMDocument();

$elementName = is_numeric($key) ? (string)$name : (string)$key;
$elementName = str_replace(array('/', ' '), '_', trim($elementName));

$node = $doc->createElement($elementName); // here I get error "invalid character name"

Образец действительного XML:

<?xml version="1.0"?>
<rows total="621" page="1">
    <row>
        <valid_name>60E49542D19D16EDB633A40</valid_name>
    ....

Надеюсь пользователям не нужно видеть в имени их элемента !, * ... Мне нужно знать, какие символы не допускаются в имени элемента, и я заменю их, вероятно, подчеркиванием, открываюсь также, если у вас есть лучшее предложение вместо замены их подчеркиванием.

Ответы [ 2 ]

1 голос
/ 31 января 2020

@ Квентин предлагает лучший способ. Использование имен узлов Dynami c означает, что вы не можете определить XSD / схему, ваши файлы XML будут только хорошо сформированы. Вы не сможете в полной мере использовать валидаторы. Таким образом, <field name="..."/> является лучшим решением с точки зрения читабельности и обслуживания компьютера.

Однако NCNames (неколонизированные имена) допускают довольно много символов. Вот что я реализовал в своей библиотеке для преобразования JSON.

$nameStartChar определяет буквы и несколько диапазонов Юникода. $nameChar добавляет еще несколько символов к этому определению (например, цифры).

Первый RegExp удаляет любой символ, который НЕ является символом имени. Второй удаляет любой начальный символ, который НЕ определен в $nameStartChar. Если результат будет пустым, он вернет имя по умолчанию.

function normalizeString(string $string, string $default = '_'): string {
    $nameStartChar =
      'A-Z_a-z'.
      '\\x{C0}-\\x{D6}\\x{D8}-\\x{F6}\\x{F8}-\\x{2FF}\\x{370}-\\x{37D}'.
      '\\x{37F}-\\x{1FFF}\\x{200C}-\\x{200D}\\x{2070}-\\x{218F}'.
      '\\x{2C00}-\\x{2FEF}\\x{3001}-\\x{D7FF}\\x{F900}-\\x{FDCF}'.
      '\\x{FDF0}-\\x{FFFD}\\x{10000}-\\x{EFFFF}';
    $nameChar =
      $nameStartChar.
      '\\.\\d\\x{B7}\\x{300}-\\x{36F}\\x{203F}-\\x{2040}';
    $result = \preg_replace(
      [
        '([^'.$nameChar.'-]+)u',
        '(^[^'.$nameStartChar.']+)u',
      ],
      '',
      $string
    );
    return empty($result) ? $default : $result;
} 

Полное имя узла XML может состоять из двух N C имен, разделенных ':'. Первая часть будет префиксом пространства имен.

$examples = [
  '123foo', 
  'foo123', 
  '  foo  ', 
  '  ', 
  'foo:bar', 
  'foo-bar'
];

foreach ($examples as $example) {
    var_dump(normalizeString($example));
}

Вывод:

string(3) "foo"
string(6) "foo123"
string(3) "foo"
string(1) "_"
string(6) "foobar"
string(7) "foo-bar"
0 голосов
/ 31 января 2020

Я бы использовал rawurlencode для декодирования имен. Вывод должен быть в порядке имен полей, и вы можете при необходимости кодировать обратно. Замена подчеркиванием сделает обратный путь невозможным.


Редактировать: Я был совершенно неправ, это не так просто. Эти две функции должны сделать свое дело:

function tag_encode(string $string): string {

    return 'tag_' . str_replace("%", "_", rawurlencode($string));
}


function tag_decode(string $string): string {

    return rawurldecode(str_replace("_", "%", substr($string, 4)));
}
  • сохранить только символы ascii в имени
  • избегать начинаться с подчеркивания или цифры.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...