Python解析具有复杂层次结构的XML - Nuke9.0v8
我正在使用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)]
我是一个视觉特效艺术家,我想总结我的周围最好的方法大脑,以解析XML文件:创建一个文件夹结构,批量创建.nk补偿文件,并插上内的数据特定的部分,因为我做我的.nk复合材料。我对于如何单独做这些事情掌握了一些东西,但是把它们全部组合在一起,并试图找到关于如此复杂的解析的教程,从而导致我停下脚步。
我知道这是很大的范围,但任何小建议都表示赞赏。
现在我有一个nuke comp,它具有一个节点树,它接受相机输入并将它们拼接成一个360度视频的latlong图像,我将把它包装成每种不同类型钻机配置的gizmo。这只是简化了创建的.nk文件,并且我可以公开可以将数据馈送到的Gizmo的各个部分。
每一天我们都会从拍摄中收到大量的镜头,我们必须为每个镜头制作一个新的.nk补偿,并将其设置为立即渲染。我想要做的就是让这些家伙创建一个首映项目并根据这个文件夹结构来组织文件。该首映式项目将作为.xml文件导出。
首映的结构设计。
- Day_01(拍摄当天)
- -^- R001(卷纸的投篮数R指的相机类型。)
- -^- R001_C001(镜头中的名称)
- ---^- Bcamera剪辑(文件路径名,视频点作为帧#)
- - Acamera夹
- --- ^(路径在点作为帧#文件名,视频) - -^- Ccamera剪辑(指向文件名的路径,作为帧#的视频点)
现在在Nuke我的脚本面板中,我可以输入哪天是xml在哪一天查找的信息。然后,假设要查看每个文件夹的名称,并使用第一个字母(R表示红色相机)并在里面寻找剪辑文件夹。然后,它使用pathurl目录作为驱动器上的摄像头文件,并且可以将数据像xml中的入点和出点一样。如果我更新针迹过程,我也有要输入模板版本的要点。这将告诉核武器使用哪个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台红外相机。
这是一个非常大的文件,所以这里是一个引擎收录:http://pastebin.com/vLaRA0X8
基本上我想约束脚本来我的变量<bin><name>'daynumber'</name>~~~~</bin>.
内寻找在这种情况下,寻找在Day_00
仓。如果根层次结构中还有其他东西,我想将其忽略为序列,未使用的剪辑和其他数据可能会非常巨大。然后我想在nk_output_dir
& dnx_render_dir
中创建daynumber
的目录,以便此拍摄日的所有内容都包含在该文件夹中。
的XML文件的恼人的部分是bin的名字是孩子的<bin>
本身,因此,一旦仓位名称被发现,该箱子的任何<children>
将树作为<name>
的同一水平。我无法找到定位标签的示例代码,然后查看处于同一分支中而不是子标签中的标签。
既然它已经找到了一天的箱子,我希望它开始寻找<children></children>
中的所有箱子。示例为<bin><name>R001</name>~~~</bin>
,并在我在nk_output_dir
& dnx_render_dir
中为Day_00文件夹中创建的目录在结构的这部分中找到的每个bin。每次相机重新加载时,会卷起到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压缩文件的名称以及写入节点上渲染的文件名称。
这里的目标是在我为nk_output_dir
选择的目录中重新创建bin文件夹结构。
dnx_render_dir
用于插入我的nuke脚本的写入节点,稍后插入到文件应该呈现到的位置。它是独立的,因为我有一个不同的RAID驱动器,它将会随着它们的填满而变化。渲染只需要放在daynumber\~rollnumber~
的目录中,但不需要将其限制在剪辑名称的文件夹中。
这里是我真正迷失的地方。现在,因为我必须考虑用户错误,所以我不能完全确定我需要进行多大的树。我知道我想要<pathurl>~</pathurl>
,我可以插入我制作的.nk(nuke)脚本。有了红色相机文件,他们可以直接在这里.R3D或文件夹结构,可以有2-3个箱子深。我知道我不能百分之百地依赖于他们如何制作这个垃圾箱的一致性。
我可以信任他们做的是确保他们是在正确的字母顺序。如果你看看这个XML,那么它们的顺序很重要。我也知道,如果我在看A R ###卷斌认为我需要3 <pathurl></pathurl>
如果IM内摹找###,我需要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>
所以一旦我解析了所有这些我想要的信息就是。
-
daynumber
中包含的XML的原始bin文件夹结构。就拿箱的名称和构建在nk_output_dir
(Day_00/R001/R001_C001等等等等)相同的文件夹结构 - 我也想在该
dnx_render_dir
文件夹daynumber
目录和每个仓引用相机胶卷目录。 - 根据clipname是否以R,G或C开头,我希望能够访问该选项以选择要制作的.nk类型。
- 我想要引用剪辑和插件的每个bin的pathurl信息。如果该剪辑有任何信息,我还想要任何
<in>
信息。这样我就可以将它插入到我的nuke gizmo的读取节点信息中。
我想我一旦弄清楚如何解析这样一个复杂的xml树,我就可以大惊小怪地摸索其余的过程。
我真的很努力寻找像这样解析一个复杂的XML文件的例子。
无论何时遇到复杂的XML,都应考虑使用XSLT脚本将XML转换为更简单的结构。作为信息,XSLT是一种特殊用途的声明性语言(与SQL类型相同),旨在将XML转换为各种结构以满足最终用途需求。像其他通用语言一样,Python使用XSLT处理器,特别是在其lxml模块中。
虽然此转换不能满足您的所有需求,但您可以为Nuke应用程序需求解析更简单的结构。目录和名称被简化并标记为日期,滚动数量,镜头名称和剪辑路径。
XSLT脚本
<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() < 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脚本(变换,解析,并导出简单的结构)(保存为的.xsl或.xslt在下面的.py脚本引用)
#!/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(包含在.py脚本中的newdom对象中)
<?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>
很长的帖子。如果你想让人们回应,可以考虑将其缩小到主要观点:问题,数据,努力和期望的结果。背景可能不是完全需要的。请记住我们是志愿者,免费提供我们的时间。 – Parfait