如何使用 C# XML 反序列化解析 FCPXML 文件

Posted

技术标签:

【中文标题】如何使用 C# XML 反序列化解析 FCPXML 文件【英文标题】:How to Parse a FCPXML file using C# XML Deserialization 【发布时间】:2021-01-16 16:06:25 【问题描述】:

我想使用 C# 解析 FCPXML 文件。 DTD is available。首先,我在 Visual Studio 2017 中打开了 DTD,并使用菜单栏项 XML->Create Schema 将其导出为 XSD。在这种特殊情况下,上面的 DTD 版本缺少 info-asc-cdl 元素,您必须从 version 1.1 of the DTD 修补它。

然后我跑了:

"c:/Program Files (x86)/Microsoft SDKs/Windows/v7.0A/bin/NETFX 4.0 Tools/x64/xsd.exe" ..\..\FcpXml\xsd\fcpxml1p8.xsd /classes /outputdir:..\..\FcpXml /namespace:LibTimeline.FcpXml

...来自构建目录。

当我尝试使用以下代码进行反序列化时:

  var serializer = new XmlSerializer(typeof(fcpxml));

  using (var reader = new StreamReader(path))
  
    fcp = (fcpxml)serializer.Deserialize(reader);
  

我得到了例外,InvalidOperationException: <fcpxml xmlns=''> was not expected. 这有点道理,因为生成的 XSD 将 targetNamespace 指定为 http://tempuri.org/fcpxml1p8

<xs:schema xmlns="http://tempuri.org/fcpxml1p8" elementFormDefault="qualified" targetNamespace="http://tempuri.org/fcpxml1p8" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="fcpxml">

但是,我正在解析的实际 XML 文件没有为根节点指定命名空间:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE fcpxml>
<fcpxml version="1.8">
    <resources>
        <format  id="r0" frameDuration="1001/30000s"  name="FFVideoFormat1080p2997"/>

推荐的处理方法是什么?如果可能的话,我想继续使用 C# XML 反序列化。 DTD -&gt; XSD -&gt; C# 流程非常好。我无法真正更改磁盘上的输入文件,因为它们是由第三方工具(Final Cut Pro、DaVinci、Premiere 等)生成的。我想一旦将 XML 加载到内存中,我就可以对其进行编辑。

请注意,我已尝试使用以下代码在 C# 中指定根节点:

  var xRoot = new XmlRootAttribute  ElementName = "fcpxml", IsNullable = false ;
  var serializer = new XmlSerializer(typeof(fcpxml), xRoot);
  using (var reader = new StreamReader(path))
  
    fcp = (fcpxml)serializer.Deserialize(reader);
  

这使我可以毫无例外地反序列化根节点(及其属性),但没有一个子节点被反序列化。我相信这是因为他们没有预期的命名空间。

【问题讨论】:

调用xsd.exe的时候能控制URI吗? docs.microsoft.com/en-us/dotnet/standard/serialization/… @MikeJ,是的。我可以手动编辑它。 看看 xsd.exe 的 args,你不能控制你在下面的答案中删除的两个属性吗? 如果您知道这样做的论据,请分享。我在写答案的时候找了一个,我没有看到任何符合这个目的的东西。 【参考方案1】:

如果从生成的 XSD 文件的根元素中删除以下两个属性:

xmlns="http://tempuri.org/fcpxml1p8"
targetNamespace="http://tempuri.org/fcpxml1p8"

...并重新生成类,它将反序列化整个结构,并且您不必包含 xRoot 参数。

var serializer = new XmlSerializer(typeof(fcpxml));
using (var reader = new StreamReader(path))

    doc = (fcpxml)serializer.Deserialize(reader);

【讨论】:

我尝试了您的建议并将xmlnstargetNamespace 设置为生成的XSD 根元素中的空字符串。我现在可以反序列化了。谢谢!我认为这是适合我情况的最佳做法... 好的。完全删除属性是您建议的。这也很好用。 由于 XSD 文件应该只需要生成一次并且生成的内容不正确,因此在生成后修补这些属性是安全的(但请记录您所做的事情,以防您必须为 1.9 重新生成 XSD !)。对于这种情况,这可能是“最好的”。如果您必须定期重新生成,我建议您编写一个小型实用程序来对文件进行后处理,以便每次都能始终如一地完成。 我不这么认为。 XSD 是使用菜单项 XML > Create Schema 生成的,它仅使用在编辑器中打开的 DTD 作为输入来生成 XSD,因此它使用 tempuri.org 和基本文件名(用于路径)合成了这些属性. xsd.exe 有一个/namespace: 开关,但它指定要生成的类的命名空间。我没有看到用 xsd.exe 覆盖命令行输入架构中的xmlnstargetNamespace 属性值的方法。 我知道编辑架构似乎有点像 hack,但您还必须考虑来源:它不是官方的 XSD。它基于官方的 DTD,但 DTD 是有限的,据我所知,它没有任何命名空间的概念。我认为这将是一个很少需要采取的行动,所以只要手动步骤——1)从旧版本修补info-asc-cdl元素定义,以及2)修复目标命名空间——记录在案,回归将很容易避免下次。希望info-asc-cdl 问题能够得到解决,并且可以删除该步骤。

以上是关于如何使用 C# XML 反序列化解析 FCPXML 文件的主要内容,如果未能解决你的问题,请参考以下文章

创建 C# 模型以反序列化 XML 提要

C#从xml反序列化日期时间

如何反序列化 C# 中只有属性的 xml 元素?

C# 在忽略命名空间的同时反序列化 xml

如何将 XML 反序列化为 C# 中的对象? [复制]

如何反序列化 C# 对象中复杂的 XML 格式并读取它以使用其值?