温馨提示:本文翻译自stackoverflow.com,查看原文请点击:php - Invalid characters in XML tag name
php xml dom

php - XML标签名称中的字符无效

发布于 2020-03-27 16:20:23

我们有一个庞大的数据库,用户可以在其中创建自定义字段。名称中允许使用每个UTF-8字符。直到几周前,当他们以XML导出数据时,只有用户在表中拥有的无效字符才是斜杠/和空格字符,我们用下划线代替了它们。

现在我看到一些谁需要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>
    ....

I don't need for users to see in their element name !, *... I need to know what are characters that aren't allowed to be in element name, And I will replace them probably with an underscore, I am opened also if you have better proposition instead of replacing them with an underscore.

查看更多

查看更多

提问者
Ivan Vulović
被浏览
106
ThW 2020-01-31 20:33

@Quentin suggest the better way. Using dynamic node names mean that you can not define an XSD/Schema, your XML files will be wellformed only. You will not be able to make full use of validators. So a <field name="..."/> is a better solution from a machine readability and maintenance point of view.

However, NCNames (non-colonized names) allow for quite a lot characters. Here is what I implemented in my library for converting JSON.

$nameStartChar定义字母和几个Unicode范围。$nameChar在该定义中添加更多字符(例如数字)。

第一个RegExp删除任何不是名称char的字符。第二个命令删除所有未在中定义的起始字符$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节点名称可以包含两个以':'分隔的NC名称。第一部分是名称空间前缀。

$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"