首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用C#,我如何关闭格式错误的XML标记?

使用C#,我如何关闭格式错误的XML标记?
EN

Stack Overflow用户
提问于 2012-04-06 11:15:29
回答 4查看 2.4K关注 0票数 3

背景

我继承了大量XML文件,这些文件始终包含一个带有两个开始的标记,而不是一个开始和一个结束。我需要遍历所有这些文件并更正格式错误的XML。

下面是一个不好的XML的简化示例,它是每个文件中完全相同的标记:

代码语言:javascript
运行
复制
<meals>
    <breakfast>
         Eggs and Toast
    </breakfast>
    <lunch>
         Salad and soup
    <lunch>
    <supper>
         Roast beef and potatoes
    </supper>
</meals>

注意,<lunch>标记没有闭包。这在所有文件中都是一致的。

问题

使用C#的regex来解决这个问题是最好的吗?如果是这样的话,我该怎么做呢?

我已经知道如何迭代文件系统并将文档读入XML或string对象,因此您不需要回答这一部分。

谢谢!

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-04-06 11:58:06

我认为,如果情况真的像你所描述的那样简单,那么正则表达式就有点过分了(例如,它总是相同的标签,而它们总是只有一个)。如果XML文件相对较小(千字节,而不是兆字节),那么可以将整个文件加载到内存中,使用字符串操作插入缺少的斜杠,然后就到此为止。这将比尝试使用正则表达式更有效(更快)。如果您的文件非常大,您可以将其修改为逐行读取文件,直到它找到第一个<lunch>标记,然后查找下一个标记并进行相应的修改。下面是一些代码,供您开始使用:

代码语言:javascript
运行
复制
var xml = File.ReadAllText( @"C:\Path\To\NaughtyXml.xml" );

var firstLunchIdx = xml.IndexOf( "<lunch>" );
var secondLunchIdx = xml.IndexOf( "<lunch>", firstLunchIdx+1 );

var correctedXml = xml.Substring( 0, secondLunchIdx + 1 ) + "/" +
xml.Substring( secondLunchIdx + 1 );

File.WriteAllText( @"C:\Path\To\CorrectedXml.xml", correctedXml );
票数 2
EN

Stack Overflow用户

发布于 2012-04-06 11:57:43

如果损坏的XML相对简单,如您在问题中所示,那么您可以使用一些简单的逻辑和基本的正则表达式。

代码语言:javascript
运行
复制
    public static void Main(string[] args)
    {
        string broken = @"
<meals>
    <breakfast>
         Eggs and Toast
    </breakfast>
    <lunch>
         Salad and soup
    <lunch>
    <supper>
         Roast beef and potatoes
    </supper>
</meals>";

        var pattern1 = "(?<open><(?<tag>[a-z]+)>)([^<]+?)(\\k<open>)";
        var re1 = new Regex(pattern1, RegexOptions.Singleline);

        String work = broken;
        Match match = null;
        do
        {
            match = re1.Match(work);
            if (match.Success)
            {
                Console.WriteLine("Match at position {0}.", match.Index);
                var tag = match.Groups["tag"].ToString();

                Console.WriteLine("tag: {0}", tag.ToString());

                work = work.Substring(0, match.Index) +
                    match.Value.Substring(0, match.Value.Length - tag.Length -1) +
                    "/" +
                    work.Substring(match.Index + match.Value.Length - tag.Length -1);

                Console.WriteLine("fixed: {0}", work);
            }
        } while (match.Success);
    }

该正则表达式使用.NET正则表达式的“命名”捕获组特性。?<open>表示通过括号捕获的组将可以通过名称"open“进行访问。该分组捕获开始标记,包括尖括号。它假定开始标记上没有xml属性。在该分组中,还有另一个命名组-这个组使用名称" tag“并捕获标记名称本身,没有尖括号。

然后,正则表达式懒惰地捕获一堆中间文本((.+?)),然后捕获另一个“打开”标记,该标记使用反向引用指定。惰性捕获在那里,所以它不会吞噬文本中任何可能插入的开始标记。

因为XML可能跨越多个换行符,所以需要RegexOptions.Singleline

然后,该逻辑在循环中应用此正则表达式,将任何匹配的文本替换为具有结束标记的固定版本有效的xml。固定的XML是通过简单的字符串切片生成的。

在以下情况下,此正则表达式将不起作用:

  • 开始标记上有XML属性
  • 有奇怪的空格-尖括号之间的空格包含标记名称
  • 标记名称使用短划线或数字或任何不是小写ASCII的字符串之间包括尖括号(在CDATA中)

...but这种方法仍然有效。你只需要稍微调整一下。

票数 3
EN

Stack Overflow用户

发布于 2012-04-06 12:08:07

如果您的xml文件中唯一的问题是您所显示的内容,那么Chesso的答案应该可以满足需要。事实上,我会走这条路,即使它完全满足了我80-90%的需求-其余的情况下,我可能会选择手动处理或编写特定的处理代码。

说,如果文件结构是复杂的,而不是你所描述的简单,那么你可能应该看看一些文本词法分析器,它将允许你将你的文件内容分解成标记。检查和纠正不规则性的标记语义分析必须由您完成,但至少解析文本会简单得多。请参阅下面几个链接到C#中词法分析的资源:

  1. http://blogs.msdn.com/b/drew/archive/2009/12/31/a-simple-lexer-in-c-that-uses-regular-expressions.aspx
  2. Poor man's "lexer" for C#
  3. http://www.seclab.tuwien.ac.at/projects/cuplex/lex.htm
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10038722

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档