I'd like to parse a FCPXML file using C#. The 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.
Then I ran:
"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
...from the build directory.
When I attempt to deserialize using the following code:
var serializer = new XmlSerializer(typeof(fcpxml));
using (var reader = new StreamReader(path))
{
fcp = (fcpxml)serializer.Deserialize(reader);
}
I get the exception, InvalidOperationException: <fcpxml xmlns=''> was not expected.
That kinda makes sense since the generated XSD specifes the targetNamespace as 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">
However, the actual XML file I'm parsing doesn't specify a namespace for the root node:
<?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"/>
What's the recommended way of dealing with this? I'd like to continue using C# XML Deserialization if at all possible. The DTD -> XSD -> C#
flow is really nice. I can't really change the input files on disk since they're generated by third-party tools (Final Cut Pro, DaVinci, Premiere, etc.). I suppose I could edit the XML once it's loaded into memory.
Note that I have tried specifying the root node in my C# using the following code:
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);
}
This allows me to deserialize the root node (and its attributes) without exceptions, but none of the child nodes get deserialized. I believe this is because they don't have the expected namespace.
If you remove the following two attributes from the generated XSD file's root element:
xmlns="http://tempuri.org/fcpxml1p8"
targetNamespace="http://tempuri.org/fcpxml1p8"
...and regenerate the classes, it will deserialize the full structure, and you don't have to include the xRoot
argument.
var serializer = new XmlSerializer(typeof(fcpxml));
using (var reader = new StreamReader(path))
{
doc = (fcpxml)serializer.Deserialize(reader);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With