【问题标题】:Testing whether or not something is parseable XML in C# [duplicate]在 C# 中测试某些东西是否是可解析的 XML [重复]
【发布时间】:2013-09-09 18:28:34
【问题描述】:

有谁知道在 C# 中检查字符串是否可解析为 XML 的快速方法?最好是快速、低资源的东西,无论它是否会解析,它都会返回一个布尔值。

我正在开发一个数据库应用程序,它处理有时存储为 XML 的错误,有时不是。因此,我希望能够非常快速地测试我从数据库中获取的字符串(包含在 DataTable 中)......并且不必求助于任何 try / catch {} 语句或其他 kludges......除非这些是实现它的唯一方法。

【问题讨论】:

  • 不幸的是,在您全部阅读之前,您无法知道某些文本是有效的 XML。你得到的每一个解决方案都将是它的变体。不过,您可以找到对格式错误的 XML 负责的人,并给他们一个 XML Bozo Certification
  • 如果这是您的瓶颈,那么您能做的最好的事情就是完全放弃以 XML 格式存储内容并使用二进制格式的想法。此外,不要存储虚假值,而是以一种无需复杂分析即可立即识别类型的方式组织它。
  • @SargeBorsch 存储机制不取决于我(仅我所在楼层就有十几个开发人员);当应用程序崩溃时,错误会记录在数据库中,有时作为 XML(堆栈跟踪),有时只是一条消息。目前,我正在使用 Linq 语句将 XML 解析为更易读的格式,因为简单地将其“按原样”输出到 TextBox 有点混乱。然而,在我写完这部分之后,我开始意识到(如前所述)并非所有错误都在 XML 中,这导致 Linq 尖叫。我想我只是想要一种快速的方法来确保 Linq 可以解析 XML。

标签: c# .net xml


【解决方案1】:

听起来您有时会返回 XML,有时会返回“纯”(非 XML)文本。

如果是这种情况,您只需检查文本是否以 < 开头:

if (!string.IsNullOrEmpty(str) && str.TrimStart().StartsWith("<"))
    var doc = XDocument.Parse(str);

由于“普通”消息似乎不太可能以&lt; 开头,这可能是合理的。您唯一需要决定的是在您拥有以 &lt; 开头的非 XML 文本的边缘情况下该怎么做?

如果是我,我会默认尝试解析它并捕获异常:

if (!string.IsNullOrEmpty(str) && str.TrimStart().StartsWith("<"))
{
    try
    {
        var doc = XDocument.Parse(str);
        return //???
    }   
    catch(Exception ex)
        return str;
}
else
{
    return str;   
}

这样,您唯一有引发异常开销的情况是当您有一条以 &lt; 开头但不是有效 XML 的消息时。

【讨论】:

  • 这个答案似乎是正确的,因为问题是在寻找“我如何判断这是 XML 还是完全不同的东西” - 而不是“我如何判断这是否是完美的 XML”。如果你想更进一步,你可以尝试编写一个简短的、以安全为中心的正则表达式,它只会解析第一个 XML 元素。
  • 可能应该先做一个str.TrimStart()
  • @EkoostikMartin 补充了这一点和一个空/空检查。
  • @DStanley - 很好,这似乎是最好的答案,首先进行轻量级检查,然后进行解析。
  • 一个简单但有用的解决方案。
【解决方案2】:

您可以尝试将字符串解析为 XDocument。如果解析失败,那么你就知道它是无效的。

string xml = "";
XDocument document = XDocument.Parse(xml);

如果你不想让丑陋的 try/catch 可见,你可以把它扔到字符串类的扩展方法中......

public static bool IsValidXml(this string xml)
{
    try
    {
        XDocument.Parse(xml);
        return true;
    }
    catch
    {
        return false;
    }
}

那么你的代码看起来就像 if (mystring.IsValidXml()) {

【讨论】:

  • 这与 OP 所说的 kludge 有何不同?
  • 有时,“kludges”是最简单、最简单、最好的方法。这真的取决于情况。
  • 我认为 OP 正在寻找一些实际解析不足的东西,但我仍然不称之为 kludge。 +1
  • @Renan 您应该问的问题是,究竟是什么让这成为了一个混搭?你怎么能在不实际解析的情况下查看某些东西是否会解析?
  • @Logarr 如果您只关心它是否是有效的 XML,那么还有更轻量级的数据解析方法。您的内存占用从整个文件减少到几乎为零,处理时间大大减少等等。如果您有非常大的文件,那可能会有所作为。
【解决方案3】:

唯一能真正确定某些东西是否会真正解析的方法是……尝试解析它。

XMl 文档应该(但可能没有)在文件的开头有一个 XML 声明,跟在 BOM(如果存在)之后。它应该看起来像这样:

<?xml version="1.0" encoding="UTF-8" ?>

虽然我相信 encoding 属性是可选的(默认为 UTF-8。它也可能有一个 standalone 属性,其值为 yesno。如果存在,这是一个非常好的指标该文档假定是有效的 XML。

在@GaryWalker 的excellent answer 上翻唱,我认为这样的东西已经差不多好了(尽管设置可能需要一些调整,也许是自定义的无操作解析器)。只是为了好玩,我使用 XMark xmlgen (http://www.xml-benchmark.org/) 生成了一个 300mb 的随机 XML 文件:在我的台式机上使用下面的代码验证它需要 1.7-1.8 秒的时间。

public static bool IsMinimallyValidXml( Stream stream )
{
  XmlReaderSettings settings = new XmlReaderSettings
    {
      CheckCharacters              = true                          ,
      ConformanceLevel             = ConformanceLevel.Document     ,
      DtdProcessing                = DtdProcessing.Ignore          ,
      IgnoreComments               = true                          ,
      IgnoreProcessingInstructions = true                          ,
      IgnoreWhitespace             = true                          ,
      ValidationFlags              = XmlSchemaValidationFlags.None ,
      ValidationType               = ValidationType.None           ,
    } ;
  bool isValid ;

  using ( XmlReader xmlReader = XmlReader.Create( stream , settings ) )
  {
    try
    {
      while ( xmlReader.Read() )
      {
        ; // This space intentionally left blank
      }
      isValid = true ;
    }
    catch (XmlException)
    {
      isValid = false ;
    }
  }
  return isValid ;
}

static void Main( string[] args )
{
  string text = "<foo>This &SomeEntity; is about as simple as it gets.</foo>" ;
  Stream stream = new MemoryStream( Encoding.UTF8.GetBytes(text) ) ;
  bool isValid = IsMinimallyValidXml( stream ) ;
  return ;
}

【讨论】:

  • 完全同意,真正检查某事物是否为 XML 的唯一方法是解析整个事物。简单地检查一个或两个字符(就像其他一些答案一样)并不能保证字符串是否是 XML。 +1 用于设置;)
【解决方案4】:

我知道的测试格式良好的 XML 的最佳答案是What is the fastest way to programatically check the well-formedness of XML files in C#? formness-of-xml-file" 它涵盖了使用 XMLReader 来有效地执行此操作。

【讨论】:

  • 反对的选民请说明原因。这肯定比 XDocument.Parse() 具有更小的内存需求。
  • 我相信在将链接添加到答案之前就出现了反对意见,即便如此,这个答案也没有实质内容。
  • @Logarr 请解释一下。那里有实质。你跌倒了什么物质不正确,为什么?
  • 我最初输入了链接,但没有注意到它搞砸了,所以它是空的,大约一分钟后修复了它。不要太在意我的“分数”,但它确实解释了反对票。我认为使用 XmlReader 是实质,尤其是。因为如果您使用命名空间,该链接还提到了通过 XMLReader 中的自定义处理来避免处理延迟。我想我可以解释一下,但我认为这就是为什么我提到了一个已经很好解释的答案。
  • @Blam 答案只不过是一个链接。虽然它在 SO 上,因此不太可能成为死链接,但从链接页面发布相关摘录仍然是一种好习惯。 (为了记录,我没有对这个答案投票。只是试图使社区的反应合理化。)
猜你喜欢
  • 2016-09-27
  • 2012-09-26
  • 2012-06-04
  • 2014-05-12
  • 1970-01-01
  • 2012-01-22
  • 2021-05-15
  • 1970-01-01
相关资源
最近更新 更多