C# 从XML字符串中删除非法字符

C# 从XML字符串中删除非法字符,c#,xml,C#,Xml,我有一个包含一些XML的字符串。例如: <foo> <bar>this is < than this</bar> </foo> 这个比这个小 在将其加载到XmlDocument之前,我需要删除其中的illagal字符 任何想法 提前谢谢 我有一个包含一些Xml的字符串 不,你没有。有些类似XML的文本格式不正确。一旦它们像那样粘在一起,找到特殊的角色就很难了。哦,您可以尝试查找“”,但这些都可能出现。我的建议是后退一步,看看绳子

我有一个包含一些XML的字符串。例如:

<foo>
    <bar>this is < than this</bar>
</foo>

这个比这个小
在将其加载到
XmlDocument
之前,我需要删除其中的illagal字符

任何想法

提前谢谢

我有一个包含一些Xml的字符串

不,你没有。有些类似XML的文本格式不正确。一旦它们像那样粘在一起,找到特殊的角色就很难了。哦,您可以尝试查找“<”或“>”,但这些都可能出现。我的建议是后退一步,看看绳子是从哪里来的。更改该代码,使其处理特殊字符


在没有任何其他选项的情况下,我可能会暂时忽略XML工具(因为当您尝试给它们字符串时,它们会吐出来),并对特殊字符进行某种打开/关闭(引号为奇数/偶数)的运行计数。一旦你遇到了一个问题,我认为你在这里能做的最好的事情就是对你可能看到的东西做出明智的猜测,并尽可能地处理它们。最重要的是确保如果你的规则失败了,你不会损坏其他数据-不做任何事情就优雅地中止,并提醒管理员通常并不理想,但你可能会得到最好的结果

在您给出的示例中,数据字符串中的<后面似乎有一个空格,后面跟着空白,而构成标记一部分的<则不是。你能利用它吗

在我处理那些不符合规范的文件的经验中,你必须处理你得到的小面包屑,并向你选择的任何神祈祷,这样事情就不会进一步破裂

对不起

编辑--

我又想到了一件事。。。您正在处理的数据是严格预定义的格式吗?例如,它是否会在标记中包含可选参数?如果不是这样,那么通过使用模式,您可能会变得非常狡猾(并且让老练的开发人员稍微哭泣)

如果你知道你总是会得到这样的标签

<myData>
  <MyFirstTag>Hello, I contain illegal < data</MyFirstTag>
  <moreData>and I am just plain <B>stupid</B></moreData>
</myData>

您好,我包含非法数据
而我只是很愚蠢
您可以尝试使用一些已知且唯一的字符串(可能是guid?)标记字段定义

knownstring1
KnownString2您好,我包含非法
然后可以替换非法字符,然后将标记放回准备导入到XMLDocument中


我知道,这也让我不寒而栗,但有时你得到的数据需要你求助于肮脏的黑客。

这里有一个工具来修复你的xml中的错误:

#!/usr/bin/env perl

# Fixes unescaped "<" and "&" in between tags.

use strict;
use warnings;

use Encode qw( encode decode );

sub fix_xml {
    my ($broken_xml) = @_;

    my $enc;
    if    ( $_[0] =~ /^\xEF\xBB\xBF/ ) { $enc = 'UTF-8';    }
    elsif ( $_[0] =~ /^\xFF\xFE/     ) { $enc = 'UTF-16le'; }
    elsif ( $_[0] =~ /^\xFE\xFF/     ) { $enc = 'UTF-16be'; }
    elsif (substr($_[0], 0, 100) =~ /^[^>]* encoding="([^"]+)"/) { $enc = $1; }
    else                               { $enc = 'UTF-8';    }

    $broken_xml = decode($enc, $_[0], Encode::FB_CROAK | Encode::LEAVE_SRC);

    my $name   = qr/(?:\w+:)?\w+/x;
    my $value  = qr/(?: '[^']+' | "[^"]+" )/x;
    my $s      = qr/\s/x;
    my $attrib = qr/$name $s* = $s* $value/x;

    my $fixed_xml = '';
    for ($broken_xml) {
        /\G \z /xcg && last;

        /\G ( (?: [^<&]+ | &\#?\w+; )+               ) /xscg && do { $fixed_xml .= $1; redo };  # Text
        /\G ( < $name (?: $s+ $attrib )* $s* \/? >   ) /xscg && do { $fixed_xml .= $1; redo };  # Start or empty tag
        /\G ( <\/ $name $s* >                        ) /xscg && do { $fixed_xml .= $1; redo };  # End tag
        /\G ( <!-- (?:(?! -- ).)* -->                ) /xscg && do { $fixed_xml .= $1; redo };  # Comment
        /\G ( <!\[CDATA\[ (?:(?! \]\]> ).)* \]\]>    ) /xscg && do { $fixed_xml .= $1; redo };  # CDATA
        /\G ( <? $s* $name (?: $s+ $attrib )* $s* ?> ) /xscg && do { $fixed_xml .= $1; redo };  # Decl

        # Something illegal!
        /\G ( < ) /xscg && do { $fixed_xml .= "&#lt;";  redo };  # Unescaped "<"
        /\G ( & ) /xscg && do { $fixed_xml .= "&#amp;"; redo };  # Unescaped "&"

        die("Don't know how to fix character at position " . pos() . "\n");
    }

    return encode($enc, $fixed_xml);
}

die("usage: $0 file.xml") if !@ARGV || $ARGV[0] eq '/?' || $ARGV[0] eq '-h' || $ARGV[0] eq '--help';

my $broken_xml;
{
    open(my $fh, '<', $ARGV[0])
       or die("Can't open \"$ARGV[0]\": $!\n");
    binmode($fh);
    local $/;
    $broken_xml = <$fh>;
}

binmode(STDOUT);
print fix_xml($broken_xml);
#/usr/bin/env perl

#修复未被替换的“这是一个非常常见的场景,用于处理以某种方式遗留给您的标记。2种常见可能性:

1) 标记是由错误代码生成的,您可能有权也可能无权访问这些错误代码。您可能会发现,错误点是重复的和可预测的,您可以使用自己的代码消除这些问题:正则表达式等。如果您可以修复生成的代码,显然可以修复这些问题


2) 标记是由不知道/不关心自己在做什么的人生成的。这是一个人的问题。不要试图用代码来解决它。你必须通过与做标记的人交谈来处理它,并以这样或那样的方式处理政治。看看好的一面,也许你可以让你的老板来做。

如果这是真的,我明白你的意思一个选项我本来已经做过了,所以你没有编写字符串的代码?你和另一个应用程序有某种合同,它应该给你XML,但它不是。推进它。你正在设置一个非常艰巨的任务。例如,考虑<代码> <代码>。没有什么类似的,我正在寻找获得Ro的可能性。在到达这个阶段之前,通过解析文本,但不解释应用程序的复杂性,这是剥离非法字符的最佳场所之一。相信我……我知道这将是一个痛苦的地方。我可以同情这里的OP,Kate。我曾经不得不处理一个大型且非常知名的应用程序的数据硬件和软件公司,假设是CSV文件。数据以逗号分隔,以引号分隔,但在数据项中包含引号和逗号。用肉眼解析已经足够困难了,更不用说编写一个能够自动处理的解析器了。供应商(他们是谁)不会更改格式,所以我们必须尽最大努力使其工作。这可能会工作…可能比这更棘手,但我认为您已经给了我一些可以使用的东西。我必须在早上头脑清醒时尝试。谢谢。我将从其他开发人员那里提取这段可爱的代码。它可能是我们肮脏的秘书arghh Perl:S我是一个C#man,这可能是一场噩梦转换…可能吗?@mjmcloug,为什么要转换它?C#肯定可以启动程序,或者你可以在将它们传递给你的程序之前先修复它们。
#!/usr/bin/env perl

# Fixes unescaped "<" and "&" in between tags.

use strict;
use warnings;

use Encode qw( encode decode );

sub fix_xml {
    my ($broken_xml) = @_;

    my $enc;
    if    ( $_[0] =~ /^\xEF\xBB\xBF/ ) { $enc = 'UTF-8';    }
    elsif ( $_[0] =~ /^\xFF\xFE/     ) { $enc = 'UTF-16le'; }
    elsif ( $_[0] =~ /^\xFE\xFF/     ) { $enc = 'UTF-16be'; }
    elsif (substr($_[0], 0, 100) =~ /^[^>]* encoding="([^"]+)"/) { $enc = $1; }
    else                               { $enc = 'UTF-8';    }

    $broken_xml = decode($enc, $_[0], Encode::FB_CROAK | Encode::LEAVE_SRC);

    my $name   = qr/(?:\w+:)?\w+/x;
    my $value  = qr/(?: '[^']+' | "[^"]+" )/x;
    my $s      = qr/\s/x;
    my $attrib = qr/$name $s* = $s* $value/x;

    my $fixed_xml = '';
    for ($broken_xml) {
        /\G \z /xcg && last;

        /\G ( (?: [^<&]+ | &\#?\w+; )+               ) /xscg && do { $fixed_xml .= $1; redo };  # Text
        /\G ( < $name (?: $s+ $attrib )* $s* \/? >   ) /xscg && do { $fixed_xml .= $1; redo };  # Start or empty tag
        /\G ( <\/ $name $s* >                        ) /xscg && do { $fixed_xml .= $1; redo };  # End tag
        /\G ( <!-- (?:(?! -- ).)* -->                ) /xscg && do { $fixed_xml .= $1; redo };  # Comment
        /\G ( <!\[CDATA\[ (?:(?! \]\]> ).)* \]\]>    ) /xscg && do { $fixed_xml .= $1; redo };  # CDATA
        /\G ( <? $s* $name (?: $s+ $attrib )* $s* ?> ) /xscg && do { $fixed_xml .= $1; redo };  # Decl

        # Something illegal!
        /\G ( < ) /xscg && do { $fixed_xml .= "&#lt;";  redo };  # Unescaped "<"
        /\G ( & ) /xscg && do { $fixed_xml .= "&#amp;"; redo };  # Unescaped "&"

        die("Don't know how to fix character at position " . pos() . "\n");
    }

    return encode($enc, $fixed_xml);
}

die("usage: $0 file.xml") if !@ARGV || $ARGV[0] eq '/?' || $ARGV[0] eq '-h' || $ARGV[0] eq '--help';

my $broken_xml;
{
    open(my $fh, '<', $ARGV[0])
       or die("Can't open \"$ARGV[0]\": $!\n");
    binmode($fh);
    local $/;
    $broken_xml = <$fh>;
}

binmode(STDOUT);
print fix_xml($broken_xml);