【问题标题】:Extract part of text, which is JSON or XML提取部分文本,即 JSON 或 XML
【发布时间】:2018-07-30 13:43:47
【问题描述】:

假设我们有以下文本:

Something1 { "prop": "value" } Something2 <?xml version="1.0" encoding="UTF-8"?>
<root><subnode /></root> Something3

有没有一种简单的方法可以把这个字符串分成几部分:

  • 文字,Something1
  • JSON, { "prop": "value" }
  • 文字,Something2
  • XML, <?xml version="1.0" encoding="UTF-8"?> <root><subnode /></root>
  • 文字,Something3

我只考虑 JSON 和 XML 格式。

目前我有两个想法:

  • 逐字符解析字符串;如果字符是“{”,则手动检查它是否是 JSON(解析),如果是,则使用 Newtonsoft JSON 解析。如果字符是“
  • 既然很清楚,当 JSON 和 XML 结束时,JSON 和 XML 反序列化器应该能够说“可解析的数据到此结束”。如果是这样,当遇到 '{' 或 '

我将第一个选项视为最后的手段 - 这是很多工作,我不确定我是否会涵盖所有 JSON/XML 警告。第二种可能吗(尤其是使用 System.XML 和一些流行的 JSON 反序列化器,例如 Newtonsoft.JSON)?

或者有没有更好的方法来解决这个问题?

【问题讨论】:

  • 这感觉像是一个 XY 问题 - meta.stackexchange.com/questions/66377/what-is-the-xy-problem。为什么需要这样做?这种格式的数据是从哪里来的?
  • 通过一些努力,您应该能够实现选项 2。例如:JToken.ReadFrom()(来自 Newtonsort.JSON 库)不会抛出异常,您将它提供给它 json 对象,然后是任何东西 - 它只会解析json 对象。
  • @mjwillis 此数据是一个日志条目,可能如下所示:Server response: {"field": "value"}。我想把它分成几部分,自动格式化和可视化。由于我的应用程序通常用于显示日志,因此我无法知道日志条目的格式。

标签: c# json xml parsing


【解决方案1】:

将这个特定的文本分成几个部分很容易。编写一个程序来获取一组与此类似的可能输入并对它们中的每一个执行类似的处理是比较棘手的:因为它取决于它们的“相似程度”。

通过在 BNF 中编写语法来指定一类“相似”输入,而通过编写解析器来拆分符合该语法的文本。这都是成熟的计算机科学,完全符合任何本科课程的教学内容。为您要处理的消息集编写一个明确的 BNF 规范,剩下的就一帆风顺了。

不幸的是,对于 JSON 或 XML 等语言的解析器来说,让输入流处于您可以从 JSON 或 XML 完成的位置继续读取的状态并不常见(相反,它们会抛出一个如果在 JSON 或 XML 结构的末尾之外还有更多内容,则会出错)。它有时会是一个方便的功能,但通常不可用。

【讨论】:

  • “(相反,如果JSON或XML结构的末尾还有更多内容,他们会抛出错误)” - 我实际上是用它来实现一个解决方案:)
【解决方案2】:

我设法实施了一个解决方案。简而言之,当它遇到 { 或

我想它不会在每种情况下都有效,有时它可能会产生意想不到的结果(例如 XML 中的 JSON),但对于我的需要来说已经足够了。

使用 ValueTuple。您还必须为已识别的部分(SimpleTextPart、XmlTextPart、JsonTextPart)实现自己的容器。

private int Move(string text, int current, int line, int position)
{
    while (current < text.Length && (line > 1 || position > 1))
    {
        if (text[current] == '\n')
        {
            if (line == 1)
                return -1;

            line--;
        }
        else if (line == 1)
        {
            position--;
        }

        current++;
    }

    return current;
}

private (bool jsonParseResult, BaseTextPart part, int newIndex) TryParseJson(string text, int current)
{
    try
    {
        string textPart = text.Substring(current);

        JObject obj = JObject.Parse(textPart);

        return (true, new JsonTextPart(obj), text.Length);
    }
    catch (JsonReaderException e)
    {
        int end = Move(text, current, e.LineNumber, e.LinePosition);

        try
        {
            string textPart = text.Substring(current, end - current);

            JObject obj = JObject.Parse(textPart);

            return (true, new JsonTextPart(obj), end);
        }
        catch (JsonReaderException)
        {
            return (false, null, 0);
        }
    }
}

private (bool xmlParseResult, BaseTextPart part, int newIndex) TryParseXml(string text, int current)
{
    XmlDocument doc = new XmlDocument();

    try
    {
        string textPart = text.Substring(current);

        doc.Load(new StringReader(textPart));    

        return (true, new XmlTextPart(doc), text.Length);
    }
    catch (XmlException e)
    {
        int end = Move(text, current, e.LineNumber, e.LinePosition);

        try
        {
            string textPart = text.Substring(current, end - current);

            doc.Load(new StringReader(textPart));

            return (true, new XmlTextPart(doc), end);
        }
        catch (XmlException)
        {
            return (false, null, 0);
        }
    }
}


private List<BaseTextPart> Parse(string text)
{
    var result = new List<BaseTextPart>();

    int current = 0;
    StringBuilder buffer = new StringBuilder();
    while (current < text.Length)
    {
        if (text[current] == '{')
        {
            (bool jsonParseResult, BaseTextPart part, int newIndex) = TryParseJson(text, current);

            if (jsonParseResult)
            {
                if (buffer.Length > 0)
                {
                    result.Add(new SimpleTextPart(buffer.ToString()));
                    buffer.Clear();
                }

                result.Add(part);
                current = newIndex;
                continue;
            }
        }

        if (text[current] == '<')
        {
            (bool xmlParseResult, BaseTextPart part, int newIndex) = TryParseXml(text, current);

            if (xmlParseResult)
            {
                if (buffer.Length > 0)
                {
                    result.Add(new SimpleTextPart(buffer.ToString()));
                    buffer.Clear();
                }

                result.Add(part);
                current = newIndex;
                continue;
            }
        }

        buffer.Append(text[current]);
        current++;
        continue;
    }

    if (buffer.Length > 0)
    {
        result.Add(new SimpleTextPart(buffer.ToString()));
        buffer.Clear();
    }

    return result;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多