2016-03-01 7 views
2

Я работаю с NukeX9.0v8, Adobe Premiere Pro CC 2015 и запускает внутренний прерыватель python.Python Анализ XML со сложной иерархией - Nuke9.0v8

# Result: 2.7.3 (default, Jul 24 2013, 15:50:23) 
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] 

Я VFX художником, и я стараюсь, чтобы обернуть мой мозг вокруг лучшего метода для разбора XML-файлов для того, чтобы: создать структуру папок, пакетные создать .nk аккомпанемента файлы и подключить данные в пределах когда я делаю свои .nk comps. Я немного разбираюсь в том, как делать каждую из этих вещей изолированно, но подключать все это вместе и пытаться найти учебники по таким сложным синтаксическим анализам, чтобы остановить меня.

Я знаю, что этот масштаб большой, но любые небольшие советы приветствуются.

Прямо сейчас у меня есть nuke comp, у которого есть дерево узлов, которое принимает входные данные камеры и сшивает их в латинское изображение для 360 видео, я собираюсь обернуть это в gizmo для каждого типа конфигурации буровой установки. Это просто упрощает создаваемые .nk-файлы, и я могу разоблачить части этой вещицы, в которую я могу подавать данные.

Каждый день мы получаем тонну отснятого материала от съемок, и мы должны сделать новый .nk comp для каждого снимка и установить его для рендеринга сразу. То, что я хочу сделать, это заставить парней на съемочной площадке создать проект премьеры и организовать файлы на основе этой структуры папок. Этот проект премьеры будет экспортирован как XML-файл.

Дизайн структуры в премьере.

  • Day_01 (день съемок)
  • -^- R001 (номер Рулон для снимков R со ссылкой на тип камеры.)
  • -^- R001_C001 (Название выстрела)
  • ---^- Acamera клип (путь к файлу имя, видео в точку, как кадр #)
  • ---^- Bcamera клип (путь к файлу имя, видео в точку, как кадр #)
  • - -^- клип Ccamera (путь к имени файла, видео в виде кадра #)

Прямо сейчас на моей панели скриптов внутри Nuke я могу ввести информацию о том, где находится xml для дня, в какой день нужно искать. Затем, предположим, нужно заглянуть в каждое имя папки для рулона и использовать первую букву (R для RED-камеры) и посмотреть папку для клипа. Затем он использует каталог pathurl для файлов камеры на диске, а также может принимать данные как точки входа и выхода, если они присутствуют в xml. У меня также есть пункты для ввода версии шаблона, если я обновляю процесс стежка. Это скажет, что nuke comp, какой gizmo использовать.

Вот моя панель в Nuke.

def sesquixmlparse(): 
''' 
This imports the xml file from premiere. It looks for the bin that it is working for today and starts looking in what is inside the bins 
It then sees the bins inside and uses them to create nuke scripts with these as inputs 
It asks what template version to use for the rig. things change or maybe even get better 
''' 

# Lets build the Nuke Panel that tells us our inputs 
p = nuke.Panel("Sesqui XML Parse for Dailies") 
xml_file = 'Daily XML' 
daynumber = 'Day_##' 
nk_output_dir = 'Directory to build VFX folder structure' 
dnx_render_dir = 'Directory for write nodes' 
r_template_vr = 'VER1' 
g_template_vr = 'VER1' 
c_template_vr = 'VER1' 

p.addFilenameSearch("Daily XML", xml_file) 
p.addSingleLineInput("Bin to process", daynumber) 
p.addFilenameSearch("Directory to build VFX folder structure", nk_output_dir) 
p.addFilenameSearch("Directory to render from write nodes", dnx_render_dir) 
p.addSingleLineInput("3 Red stmap version", r_template_vr) 
p.addSingleLineInput("6 Gopro stmap verison", g_template_vr) 
p.addSingleLineInput("5 Canon stmap verison", c_template_vr) 
p.setWidth(600) 
print "Panel created" 
if not p.show(): 
    return 

# Assign var from nuke panel user-entered data 
xml_file = p.value("Daily XML") 
daynumber = p.value("Bin to process") 
nk_output_dir = p.value("Directory to build VFX folder structure") 
dnx_render_dir = p.value("Directory to render from write nodes") 
r_template_vr = p.value("3 Red stmap version") 
g_template_vr = p.value("6 Gopro stmap verison") 
c_template_vr = p.value("5 Canon stmap verison") 
print "var's assigned from panel" 

# Create paths for render directory if it does not exist 
if not os.path.isdir(dnx_render_dir): 
    os.mkdir(dnx_render_dir) 
    print dnx_render_dir + " directory created" 
if not os.path.isdir(nk_output_dir): 
    os.mkdir(nk_output_dir) 
    print nk_output_dir + " directory created" 

Я в затруднении относительно того, как лучше всего читать XML-файл. Все учебники, которые я видел как на DOM, так и на elementtree, очень просты и имеют дело с прямым кодом, чтобы читать известные теги XML и разбивать данные до простого вывода str.

Мне нужно ввести переменные, которые затем сдерживают синтаксический анализ определенной части дерева и вступают в неизвестную настройку иерархии и видят, что внутри, а затем принимают решения о том, что делать с тем, что он находит.

Вот пример моего тестового XML-файла.В конечном итоге планируем использовать другие типы рулонов, которые относятся к различным типам камер, но на данный момент я просто работаю с 3-мя кратерами для фотоаппаратов.

Это очень большой файл, так вот Pastebin: http://pastebin.com/vLaRA0X8

В основном я хотел, чтобы ограничить сценарий заглянув в моей переменной <bin><name>'daynumber'</name>~~~~</bin>. В этом случае, глядя в Day_00 ведро. Если в корневой иерархии есть что-то еще, я хочу игнорировать ее как последовательности, неиспользуемые клипы и другие данные могут быть очень большими. Затем я хочу создать каталог daynumber в nk_output_dir & dnx_render_dir, так что все для этого дня съемки содержится в этой папке.

досадная часть файла XML это имя бина является дочерним по отношению к самому <bin>, так как только имя бин найден, любой <children> этого бункера будет на том же уровне дерева как <name>. Я не могу найти образец кода для размещения тега, а затем ищет работу с тегами, которые находятся в одной ветви, а не ее дочерними элементами.

Теперь, когда он нашел ящик на день, я хочу, чтобы он начал искать все ящики в <children></children>. Пример: <bin><name>R001</name>~~~</bin> и создать каталоги внутри папки Day_00, которую я сделал в nk_output_dir & dnx_render_dir для каждого бина, который он находит в этой части структуры. Каждый раз, когда перезагружается камера, которая скатывается до R002, R003 и т. Д. Также различные типы камер, такие как Gopros, будут создавать G001, G002, G003.

Тогда я хочу, чтобы искать в <children> из вышеуказанных бункеров и найти все контейнеры внутри как <bin><name>R001_C001</name>~~~</bin> и создавать папки в nk_output_dir\ daynumber \~whatever bin this is contained~\~name of this bin~\. Какой пользователь создал номер рулона и номер клипа. (R001_C001, R001_C002 и т. Д.). Это будет новое имя клипа, имя созданного .nk comp и имя файла рендеринга на узле записи.

Целью здесь является воссоздание структуры папки bin в каталоге, который я выбрал для nk_output_dir.

dnx_render_dir, предназначенный для подключения к узлам записи моих сценариев nuke позже, куда должны быть переданы файлы. Это отдельно, потому что у меня будет другой RAID-накопитель, на который он пойдет, и изменится по мере их заполнения. Оказалось, что нужно просто поместить в каталог для daynumber\~rollnumber~, но не нужно ограничивать его в папку для имени клипа.

Здесь я действительно потерян. Теперь, поскольку мне приходится учитывать пользовательскую ошибку, я не могу полностью понять, насколько глубоко в дереве мне нужно идти. Я знаю, что хочу <pathurl>~</pathurl>, который я могу подключить к скриптам .nk (nuke), которые я создаю. С красными файлами камеры они могут быть непосредственно здесь .R3D или структура папок, которые могут быть 2-3 бункера в глубину. Я знаю, что я не могу на 100% полагаться на ребята, чтобы они были последовательны в том, как они делают этот бит.

Все, что я могу им верить, это убедиться, что они находятся в правильном алфавитном порядке. Если вы посмотрите на xml, значит, порядок их важен. Я также знаю, смотрю ли я на рулонный бункер R ###, который мне нужен 3 <pathurl></pathurl>, и если im ищет внутри G ### мне нужно 6 и только для C### 5.

Порядок их важен как они могут переименовать тег имени внутри `~~~~, чтобы переименовать камеры, которые были неправильными настройками без переименования исходных файлов.(который разбивает важные метаданные, необходимые в других программах)

В этой части дерева я также хотел бы захватить <clip id=~><in>###</in>, чтобы захватить смещение рамки маркера. Если камеры не синхронизированы, и их стартовые точки могут быть установлены. Но, конечно, этот тег не является ребенком для <pathurl></pathurl> и на самом деле является 3 родителями! Также этот тег не будет на каждом клипе, поэтому я не могу его искать первым!

<clip id="masterclip-40" explodedTracks="true" frameBlend="FALSE"> 
    <uuid>85f87acc-308f-401e-bf82-55e8ea41e55a</uuid> 
    <masterclipid>masterclip-40</masterclipid> 
    <ismasterclip>TRUE</ismasterclip> 
    <duration>5355</duration> 
    <rate> 
     <timebase>30</timebase> 
     <ntsc>TRUE</ntsc> 
    </rate> 
    <in>876</in> 
    <name>B002_C002_0216AM_002.R3D</name> 
    <media> 
    <video> 
     <track> 
      <clipitem id="clipitem-118" frameBlend="FALSE"> 
       <masterclipid>masterclip-40</masterclipid> 
       <name>B002_C002_0216AM_002.R3D</name> 
       <rate> 
        <timebase>30</timebase> 
        <ntsc>TRUE</ntsc> 
       </rate> 
       <alphatype>none</alphatype> 
       <pixelaspectratio>square</pixelaspectratio> 
       <anamorphic>FALSE</anamorphic> 
       <file id="file-40"> 
        <name>B002_C002_0216AM_002.R3D</name> 
        <pathurl>file://localhost/Volumes/REDLAB_3A/SESQUI/MASTER_FILES/DAY_00/RED/R002/B002/B002_0216G4.RDM/B002_C002_0216AM.RDC/B002_C002_0216AM_002.R3D</pathurl> 

Итак, как только я разобрал все это, мне хотелось бы иметь такую ​​информацию.

  • Оригинальная структура папок bin XML, содержащаяся в daynumber. Возьмите имена бункеров и построить такую ​​же структуру папок в nk_output_dir (Day_00/R001/R001_C001 и т.д. и т.п.)
  • Я также хочу сделать daynumber каталог в папке dnx_render_dir и каталог для каждого бина, ссылающегося на рулон камеры.
  • Основываясь на том, что имя клипа начинается с R, G или C, я хочу иметь доступ к этому, чтобы выбрать, что именно .nk сделать.
  • Я хочу, чтобы информация о путях каждого бункера указывала на клип и вилку. Я также хочу получить любую информацию <in>, если она есть для этого клипа. Таким образом, я могу подключить его к информации о считываемом узле для моей гильдии nuke.

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

Я просто борюсь с поиском примеров синтаксического анализа сложного XML-файла, подобного этому.

+0

Довольно длинный пост. Если вы хотите, чтобы люди отвечали, подумайте об уменьшении этого значения до основных пунктов: проблема, данные, усилие, желаемые результаты. Предыстория не может быть полностью необходима. Пожалуйста, помните, что мы добровольцы, предоставляя наше время бесплатно. – Parfait

ответ

0

Когда вы сталкиваетесь со сложным XML, рассмотрите скрипт XSLT, чтобы преобразовать ваш XML в более простую структуру. Как информация, XSLT - это специальный, декларативный язык (тот же тип, что и SQL), предназначенный для преобразования XML в различные структуры для нужд конечного использования. Python, как и другие языки общего назначения, поддерживает XSLT-процессор, особенно в своем модуле lxml.

Хотя это преобразование не отвечает всем вашим потребностям, вы можете проанализировать более простую структуру для потребностей приложения Nuke. Каталоги и имена упрощены и помечены для daynumber, rollnumber, shotnames и клипа с помощью профайлов.

XSLT скрипт (сохранить как .xsl или .xslt ссылаться в .py скрипт ниже)

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
<xsl:output version="1.0" encoding="UTF-8" indent="yes" /> 
<xsl:strip-space elements="*"/> 

<xsl:key name="idkey" match="ctype" use="@id" /> 

    <xsl:template match="/"> 
    <root> 
     <xsl:apply-templates select="*"/> 
    </root> 
    </xsl:template> 

    <xsl:template match="xmeml/bin"> 
    <daynumber><xsl:value-of select="name"/></daynumber> 
    <xsl:apply-templates select="children/bin"/> 
    </xsl:template> 

    <xsl:template match="xmeml/bin/children/bin"> 
    <roll> 
     <rollnumber><xsl:value-of select="name"/></rollnumber> 
     <rollnumberdir><xsl:value-of select="concat(ancestor::bin/name, 
                '/', name)"/></rollnumberdir> 
     <xsl:apply-templates select="children/bin"/> 
    </roll> 
    </xsl:template> 

    <xsl:template match="xmeml/bin/children/bin/children/bin"> 
    <shot> 
     <shotname><xsl:value-of select="name"/></shotname> 
     <shotnamedir><xsl:value-of select="concat(/xmeml/bin/name, '/', 
           /xmeml/bin/children/bin/name, '/', name)"/></shotnamedir> 
     <xsl:apply-templates select="descendant::clip[position() &lt; 4]"/> 
    </shot> 
    </xsl:template> 

    <xsl:template match="clip"> 
    <clip> 
     <clipname><xsl:value-of select="descendant::name"/></clipname> 
     <xsl:copy-of select="in"/> 
     <pathurl><xsl:value-of select="descendant::pathurl"/></pathurl> 
    </clip> 
    </xsl:template> 

</xsl:transform> 

Python сценария (преобразование, анализировать и экспортировать простую структуру)

#!/usr/bin/python 
import lxml.etree as ET 

# LOAD INPUT XML AND XSLT 
dom = ET.parse('Input.xml')) 
xslt = ET.parse('XSLTScript.xsl') 

# TRANSFORM XML (SIMPLER NEWDOM CAN BE FURTHER PARSED: ITER(), FINDALL(), XPATH()) 
transform = ET.XSLT(xslt) 
newdom = transform(dom) 

# XPATH EXPRESSIONS (LIST OUTPUTS) 
daynumber = newdom.xpath('//daynumber/text()') 
# ['Day_00'] 
rolls = newdom.xpath('//rollnumber/text()') 
# ['R001', 'R002'] 
shots = newdom.xpath('//shotname/text()') 
# ['R001_C001', 'R002_C001', 'R002_C002'] 

# CONVERT TO STRING (IF NEEDED) 
tree_out = ET.tostring(newdom, encoding='UTF-8', pretty_print=True, xml_declaration=True) 
print(tree_out.decode("utf-8")) 

# OUTPUT TO FILE (IF NEEDED) 
xmlfile = open('Output.xml'),'wb') 
xmlfile.write(tree_out) 
xmlfile.close() 

ТРАНСФОРМИРОВАННЫЕ XML(содержащийся в объекте newdom в .py скрипта)

<?xml version='1.0' encoding='UTF-8'?> 
<root> 
    <daynumber>Day_00</daynumber> 
    <roll> 
    <rollnumber>R001</rollnumber> 
    <rollnumberdir>Day_00/R001</rollnumberdir> 
    <shot> 
     <shotname>R001_C001</shotname> 
     <shotnamedir>Day_00/R001/R001_C001</shotnamedir> 
     <clip> 
     <clipname>A002_C001_0216MW_001.R3D</clipname> 
     <pathurl>file://localhost/Volumes/REDLAB_3A/SESQUI/MASTER_FILES/DAY_00/RED/R001/A002/A002_0216FE.RDM/A002_C001_0216MW.RDC/A002_C001_0216MW_001.R3D</pathurl> 
     </clip> 
     <clip> 
     <clipname>A002_C001_0216MW_002.R3D</clipname> 
     <pathurl>file://localhost/Volumes/REDLAB_3A/SESQUI/MASTER_FILES/DAY_00/RED/R001/A002/A002_0216FE.RDM/A002_C001_0216MW.RDC/A002_C001_0216MW_002.R3D</pathurl> 
     </clip> 
     <clip> 
     <clipname>A002_C001_0216MW_003.R3D</clipname> 
     <pathurl>file://localhost/Volumes/REDLAB_3A/SESQUI/MASTER_FILES/DAY_00/RED/R001/A002/A002_0216FE.RDM/A002_C001_0216MW.RDC/A002_C001_0216MW_003.R3D</pathurl> 
     </clip> 
    </shot> 
    </roll> 
    <roll> 
    <rollnumber>R002</rollnumber> 
    <rollnumberdir>Day_00/R002</rollnumberdir> 
    <shot> 
     <shotname>R002_C001</shotname> 
     <shotnamedir>Day_00/R001/R002_C001</shotnamedir> 
     <clip> 
     <clipname>A003_C001_0216XI_001.R3D</clipname> 
     <pathurl>file://localhost/Volumes/REDLAB_3A/SESQUI/MASTER_FILES/DAY_00/RED/R002/A003/A003_0216XO.RDM/A003_C001_0216XI.RDC/A003_C001_0216XI_001.R3D</pathurl> 
     </clip> 
     <clip> 
     <clipname>B002_C001_02169H_002.R3D</clipname> 
     <pathurl>file://localhost/Volumes/REDLAB_3A/SESQUI/MASTER_FILES/DAY_00/RED/R002/B002/B002_0216G4.RDM/B002_C001_02169H.RDC/B002_C001_02169H_002.R3D</pathurl> 
     </clip> 
     <clip> 
     <clipname>C002_C001_02168R_001.R3D</clipname> 
     <pathurl>file://localhost/Volumes/REDLAB_3A/SESQUI/MASTER_FILES/DAY_00/RED/R002/C002/C002_0216RL.RDM/C002_C001_02168R.RDC/C002_C001_02168R_001.R3D</pathurl> 
     </clip> 
    </shot> 
    <shot> 
     <shotname>R002_C002</shotname> 
     <shotnamedir>Day_00/R001/R002_C002</shotnamedir> 
     <clip> 
     <clipname>C002_C002_0216M9_001.R3D</clipname> 
     <pathurl>file://localhost/Volumes/REDLAB_3A/SESQUI/MASTER_FILES/DAY_00/RED/R002/C002/C002_0216RL.RDM/C002_C002_0216M9.RDC/C002_C002_0216M9_001.R3D</pathurl> 
     </clip> 
     <clip> 
     <clipname>C002_C002_0216M9_002.R3D</clipname> 
     <pathurl>file://localhost/Volumes/REDLAB_3A/SESQUI/MASTER_FILES/DAY_00/RED/R002/C002/C002_0216RL.RDM/C002_C002_0216M9.RDC/C002_C002_0216M9_002.R3D</pathurl> 
     </clip> 
     <clip> 
     <clipname>C002_C002_0216M9_003.R3D</clipname> 
     <pathurl>file://localhost/Volumes/REDLAB_3A/SESQUI/MASTER_FILES/DAY_00/RED/R002/C002/C002_0216RL.RDM/C002_C002_0216M9.RDC/C002_C002_0216M9_003.R3D</pathurl> 
     </clip> 
    </shot> 
    </roll> 
</root> 
+0

Спасибо, что это именно то, что мне нужно! Интересно, что преобразованный xml возвращает все R3D-файлы (они являются натянутыми клипами) вместо первого R3D, на который ссылаются. Мне нужно будет заглянуть в структуру xml, чтобы узнать, как их оживить. – TomVR

+0

Отлично! И XSLT может обрабатывать выбор количества узлов, используя функцию 'position()'. См. Обновление с уменьшенными клипами R3D. Обязательно установите модуль lxml для запуска этого скрипта. И если этот ответ поможет, пожалуйста, примите! – Parfait