Как проанализировать файл FCPXML с помощью десериализации C # XML

#c# #xml #xsd

#c# #xml #xsd

Вопрос:

Я хотел бы проанализировать файл FCPXML с помощью C #. Доступен DTD. Для начала я открыл DTD в Visual Studio 2017 и экспортировал его как XSD, используя пункт строки меню XML->Create Schema . В данном конкретном случае в приведенной выше версии DTD отсутствует info-asc-cdl элемент, и вам необходимо исправить его с версии 1.1 DTD.

Затем я побежал:

 "c:/Program Files (x86)/Microsoft SDKs/Windows/v7.0A/bin/NETFX 4.0 Tools/x64/xsd.exe" ....FcpXmlxsdfcpxml1p8.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);
  }
  

Это позволяет мне десериализовать корневой узел (и его атрибуты) без исключений, но ни один из дочерних узлов не десериализуется. Я полагаю, это связано с тем, что у них нет ожидаемого пространства имен.

Комментарии:

1. Можете ли вы управлять URI при вызове xsd.exe ? learn.microsoft.com/en-us/dotnet/standard/serialization /…

2. @MikeJ, да. Я могу отредактировать его вручную.

3. посмотрите на аргументы, чтобы xsd.exe , разве вы не можете контролировать два атрибута, которые вы удаляете в приведенном ниже ответе?

4. Если вы знаете аргумент, который это делает, пожалуйста, поделитесь им. Я искал его во время написания ответа, и я не видел ничего, что соответствовало бы этой цели.

Ответ №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);
}
  

введите описание изображения здесь

Комментарии:

1. Я попробовал то, что вы предложили, и установил xmlns и targetNamespace для пустых строк в сгенерированном корневом элементе XSD. Теперь я могу десериализовать. Спасибо! Я полагаю, что это лучшая практика для моей ситуации…

2. ОК. Вы предложили полностью удалить атрибуты. Это тоже отлично работает.

3. Поскольку файл XSD должен быть сгенерирован только один раз, а то, что было сгенерировано, неверно, исправление этих атрибутов после генерации безопасно (но документируйте, что вы сделали, на случай, если вам придется восстанавливать XSD для версии 1.9!). Вероятно, это примерно так же «лучше», как и в данной ситуации. Если бы вам приходилось регулярно обновляться, я бы посоветовал написать небольшую утилиту, которая постобрабатывает файл, чтобы он выполнялся последовательно каждый раз.

4. Я в это не верю. XSD был сгенерирован с помощью пункта меню XML> Создать схему, который сгенерировал XSD, используя только DTD, который был открыт в редакторе в качестве входных данных, поэтому он синтезировал эти атрибуты с помощью tempuri.org и имя базового файла (для пути). xsd.exe имеет /namespace: переключатель, но он определяет пространство именклассы, которые будут созданы. Я не видел способа переопределить xmlns targetNamespace значения атрибутов и из входной схемы в командной строке с помощью xsd.exe .

5. Я знаю, что редактирование схемы кажется немного взломом, но вы также должны учитывать источник: это не официальный XSD. Он основан на официальном DTD, но DTD ограничен и, насколько я знаю, в нем нет никакого понятия о пространствах имен. Я предполагаю, что это будет редкое действие, которое нужно предпринять, поэтому, пока задокументированы ручные шаги: 1) исправление определения info-asc-cdl элемента из более старой версии и 2) исправление целевого пространства имен, регрессии будет достаточно легко избежать в следующий раз. И, надеюсь, info-asc-cdl проблема будет устранена, и этот шаг можно будет удалить.