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

How to Parse a FCPXML file using C# XML Deserialization

我想使用 C# 解析 FCPXML 文件。 DTD is available. To start, I opened the DTD in Visual Studio 2017 and exported it as an XSD using the menu bar item XML->Create Schema. In this particular case, the DTD version above is missing the info-asc-cdl element and you have to patch it in from 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 width="1920" id="r0" frameDuration="1001/30000s" height="1080" name="FFVideoFormat1080p2997"/>

推荐的处理方法是什么?如果可能的话,我想继续使用 C# XML 反序列化。 DTD -> XSD -> 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);
  }

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

如果从生成的 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);
}