【问题标题】:Custom XML-like Syntax Parsing自定义类 XML 语法解析
【发布时间】:2018-04-18 08:07:37
【问题描述】:

我正在尝试从具有控制代码的游戏中复制对话系统,这些控制代码是类似 HTML/XML 的标签,用于指示文本气泡的行为。例如,更改一段文本的颜色就像<co FF0000FF>Hello World!</co>。文本中不需要这些控制代码,所以Hello <co FF0000FF>World!</co> 或简单的Hello World 也应该解析。

我试图使它类似于 XML 以简化解析,但 XML 需要根级标记才能成功解析,并且文本可能有也可能没有任何控制代码。例如,我可以使用 XElement 解析以下内容。

string Text = "<co value=\"FF0000FF\">Hello World!</co>"
XElement.Parse(Text);

但是,以下失败并出现 XMLException(“根级别的数据无效。第 1 行,位置 1。”):

string Text = "Hello <co value=\"FF0000FF\">World!</co>"
XElement.Parse(Text);

什么是处理这个问题的好方法?有没有一种方法可以在不需要严格的 XML 语法的情况下处理解析字符串中的 XML 元素,或者是否有另一种类型的解析器可以用来实现我想要的?

【问题讨论】:

  • "Hello World!" 不是 xml。 XML 格式总是以标签开头
  • 看看 HtmlAgilityPack [html-agility-pack.net/] - 我认为它有一个宽容的 html 解析器,可能会给你更多的运气
  • 可能有一些运气,比如“Html Agility Pack”,它比 xml 松散得多......但是,坦率地说,你可能只需要从头开始编写它

标签: c# xml parsing


【解决方案1】:

如果您的类 XML 片段和真实 XML 之间的唯一区别是没有根元素,那么只需在解析之前将片段包装在一个虚拟根元素中:

parse("<dummy>" + fragment + "</dummy>")

如果还有其他差异,例如属性不在引号中,或者属性名称以数字开头,那么 XML 解析器对您来说没有多大用处,您需要自己编写。或者,如果幸运的话,validator.nu 之类的 HTML 解析器可能会处理它。

【讨论】:

    【解决方案2】:

    你可以试试HtmlAgilityPack

    通过触发此命令Install-Package HtmlAgilityPack来安装 Nuget 包

    以下示例将返回所有子节点。我没有将任何级别传递给Descendants,但您可以根据需要进一步添加更多代码。

    它将解析您的自定义格式。

    string Text = "Hello <co value=\"FF0000FF\">World!</co>";
    
    Text = System.Net.WebUtility.HtmlDecode(Text);
    HtmlDocument result = new HtmlDocument();
    result.LoadHtml(Text);
    
    List<HtmlNode> nodes = result.DocumentNode.Descendants().ToList();
    

    【讨论】:

    • 我用各种不同的控制代码测试了HtmlAgilityPack,效果非常好。谢谢!
    【解决方案3】:

    如果您的文本中的 XML 元素总是格式正确,那么您可以使用 XML 库来做到这一点。

    您可以将文本包装在根元素中并使用 XElement.Parse 并读取子节点,或者您可以使用一些较低级别的位来解析 XML 片段中的节点:

    public static IEnumerable<XNode> Parse(string text)
    {
        var settings = new XmlReaderSettings
        {
            ConformanceLevel = ConformanceLevel.Fragment
        };
    
        using (var sr = new StringReader(text))
        using (var xr = XmlReader.Create(sr, settings))
        {
            xr.MoveToContent();
    
            while (xr.EOF == false)
            {
                yield return XNode.ReadFrom(xr);
            }
        }
    }
    

    像这样使用它:

    foreach (var node in Parse("Hello <co value=\"FF0000FF\">World!</co>"))
    {
        Console.WriteLine($"{node.GetType().Name}: {node}");
    }
    

    会输出这个:

    XText: Hello
    XElement: <co value="FF0000FF">World!</co>
    

    请参阅this fiddle 以获得工作演示。

    【讨论】:

      猜你喜欢
      • 2015-03-04
      • 1970-01-01
      • 1970-01-01
      • 2014-05-15
      • 2019-01-12
      • 2023-01-21
      • 1970-01-01
      • 2018-06-14
      • 1970-01-01
      相关资源
      最近更新 更多