繁体   English   中英

如何从Perl中的字符串中删除无效的XML字符?

[英]How can I strip invalid XML characters from strings in Perl?

我正在寻找在将字符串写入XML文件之前从字符串中删除无效字符的标准,批准和强大的方法。 我在这里谈论的是包含退格(^ H)和换页字符等的文本块。

必须有一个标准的库/模块功能,但我找不到它。

我正在使用XML :: LibXML构建一个DOM树,然后我将其序列化到磁盘。

删除无效的xml-1.0字符的完整正则表达式是:

# #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
$str =~ s/[^\x09\x0A\x0D\x20-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]//go;

对于xml-1.1,它是:

# allowed: [#x1-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
$str =~ s/[^\x01-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]//go;
# restricted:[#x1-#x8][#xB-#xC][#xE-#x1F][#x7F-#x84][#x86-#x9F]
$str =~    s/[\x01-\x08\x0B-\x0C\x0E-\x1F\x7F-\x84\x86-\x9F]//go;

几乎所有人都说过,使用正则表达式。 说实话,它不够复杂,不值得添加到库中。 使用替换预处理文本。

您对上面的换行符的评论表明格式化对您来说非常重要,因此您可能必须确切地决定要替换某些字符。

XML规范中明确定义了无效字符列表(例如, http://www.w3.org/TR/REC-xml/#charsets )。 不允许的字符是ASCII控制字符栏回车,换行和制表符。 所以,你正在看一个29个字符的正则表达式字符类。 那肯定不是太糟糕。

就像是:

$text =~ s/[\x00-\x08 \x0B \x0C \x0E-\x19]//g;

应该这样做。

我找到了一个解决方案,但它使用iconv命令而不是perl。

$ iconv -c -f UTF-8 -t UTF-8 invalid.utf8 > valid.utf8

以上基于正则表达式给出的解决方案不起作用!! ,请考虑以下示例:

$ perl -e 'print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<root>\x{A0}\x{A0}</root>"' > invalid.xml
$ perl -e 'use XML::Simple; XMLin("invalid.xml")'
invalid.xml:2: parser error : Input is not proper UTF-8, indicate encoding !
Bytes: 0xA0 0xA0 0x3C 0x2F
$ perl -ne 's/[^\x09\x0A\x0D\x20-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]//go; print' invalid.xml > valid.xml
$ perl -e 'use XML::Simple; XMLin("valid.xml")'
invalid.xml:2: parser error : Input is not proper UTF-8, indicate encoding !
Bytes: 0xA0 0xA0 0x3C 0x2F

实际上, invalid.xmlvalid.xml这两个文件是相同的

问题是范围“\\ x20- \\ x {D7FF}”匹配那些unicode字符的有效表示,但不匹配例如无效字符序列“\\ x {A0} \\ x {A0}”。

翻译是比正则表达式替换快了很多 特别是如果您想要删除所有字符。 使用newt的集合:

$string_to_clean =~ tr/\x00-\x08\x0B\x0C\x0E-\x19//d;

像这样的测试:

cmpthese 1_000_000
       , { translate => sub { 
               my $copy = $text; 
               $copy =~ tr/\x00-\x08\x0B\x0C\x0E-\x19//d; 
           }
           , substitute => sub { 
               my $copy = $text; 
               $copy =~ s/[\x00-\x08\x0B\x0C\x0E-\x19]//g; 
           }
         };

yeilded:

                Rate substitute  translate
substitute  287770/s         --       -86%
translate  2040816/s       609%         --

我需要删除更快的tr所需的字符越多。

如果您使用XML库来构建XML(而不是字符串连接,简单模板等),那么它应该为您解决这个问题。 重新发明轮子毫无意义。

好吧,这似乎已经回答了,但是嘿。 如果要创作XML文档,则必须使用XML库。

#!/usr/bin/perl
use strict;
use XML::LibXML;

my $doc = XML::LibXML::Document->createDocument('1.0');
$doc->setURI('http://example.com/myuri');
$doc->setDocumentElement($doc->createElement('root-node'));

$doc->documentElement->appendTextChild('text-node',<<EOT);
    This node contains &, ñ, á, <, >...
EOT

print $doc->toString;

这产生以下结果:

$ perl test.pl
<?xml version="1.0"?>
<root-node><text-node>    This node contains &amp;, &#x6C821;, &lt;, &gt;...
</text-node></root-node>

编辑:我现在看到你已经在使用XML :: LibXML。 这应该可以解决问题。

您可以使用正则表达式删除控制字符,例如\\ cH将匹配\\ cL或\\ x08和\\ x0C分别匹配退格和Formfeed。

你可以使用一个简单的正则表达式来查找和替换你的文本块中的所有控制字符,用空格替换它们或者完全删除它们 -

# Replace all control characters with a space
$text =~ s/[[:cntrl:]]/ /g;

# or remove them
$text =~ s/[[:cntrl:]]//g;

我之前没有对包含“无效”字符的XML做过很多工作,但在我看来,这里有两个完全不同的问题。

首先,您可能不需要数据中的字符。 您应该决定它们是什么以及如何删除/替换它们,而不受任何XML限制的影响。 例如,你可能有x^H_y^H_z^H_ ,你决定要删除退格和后面的字符。 或者你可能实际上不想调整你的数据,但是由于需要用XML表示它而感到被迫。

更新:我为后代保留了以下段落,但它们基于一个误解:我认为你可以在XML数据中包含任何字符,只要你正确编码它,但似乎有一些字符完全是verboten,甚至编码? XML :: LibXML剥离这些(至少当前版本这样做),除了nul字符,它将其视为字符串的结尾,丢弃它以及随后的任何内容:(

其次,您可能在数据中包含需要以XML格式编码的字符。 理想情况下,您使用的任何XML模块都可以为您执行此操作,但如果不是,您应该能够手动执行此操作,例如:

use HTML::Entities "encode_entities_numeric";
$encoded_string = encode_entities_numeric( $string, "\x00-\x08\x0B\x0C\x0E-\x19");

但这真的只是权宜之计。 使用适当的XML模块; 比如看看这个答案

Axeman关于使用tr的权利,但是他和newt在反转XML规范的合法字符方面犯了一点错误。 http://www.w3.org/TR/REC-xml/#charsets给出

Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]

由于\\x20之前的十六进制数是\\x1F (不是\\x19 !),你应该使用

$string_to_clean =~ tr/\x00-\x08\x0B\x0C\x0E-\x1F//d;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM