我们有一个庞大的数据库,用户可以在其中创建自定义字段。名称中允许使用每个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>
....
我不需要用户在其元素名称!
,*
中看到...我需要知道元素名称中不允许包含哪些字符,可能会用下划线替换它们,如果您有更好的主张而不是用下划线替换它们,我也将开放。
答案 0 :(得分:1)
@Quentin建议使用更好的方法。使用动态节点名称意味着您无法定义XSD / Schema,XML文件只会格式正确。您将无法充分利用验证程序。因此,从机器可读性和维护的角度来看,<field name="..."/>
是更好的解决方案。
但是,NCName(非冒号名称)允许使用很多字符。这是我在库中实现的用于转换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"
答案 1 :(得分:-1)
我将使用rawurlencode来解码名称。作为字段名称,输出应该可以,并且您可以根据需要进行编码。用下划线代替将无法实现相反的操作。
编辑: 我错了,这并不容易。这两个功能应该可以解决问题:
<ItemsControl ItemsSource="{Binding Questions}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="8*"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Content="{Binding RequiredText}" />
<TextBox x:Name="textBox" Grid.Column="1" Text="{Binding InputText}">
<TextBox.Style>
<Style TargetType="TextBox">
<Setter Property="BorderBrush" Value="Red" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsCorrect}" Value="true">
<Setter Property="BorderBrush" Value="Green" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>