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