Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Parse a FCPXML file using C# XML Deserialization

Tags:

c#

xml

xsd

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.

like image 361
watkipet Avatar asked Sep 13 '25 01:09

watkipet


1 Answers

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);
}

enter image description here

like image 79
madreflection Avatar answered Sep 14 '25 15:09

madreflection