PDA

View Full Version : XML "parameterid" manipulations




initialsBB
Jun 11, 2011, 04:55 AM
Hi,
Don't know if programming is the right place for this thread, but it seems to me the best place to look.

I would like to know if anyone can help me figure out how to manipulate an XML file exported by Final Cut Pro. FCP allows batch changing properties like scale, position, rotation, of a text generator inside it's timeline, but it does not allow batch changing of text-specific properties such as font size, font color, etc, but all these properties can be seen inside an XML export of the sequence.

I would like to change the font color from white to yellow, can't realistically be done manually as there are hundreds of text generators (it's a subtitle track). I tried opening the XML in TextEdit and doing a find & replace but it won't find all the occurrences of this block below:


<parameter>
<parameterid>textcolor</parameterid>
<name>Text Color</name>
<value>
<alpha>255</alpha>
<red>235</red>
<green>235</green>
<blue>235</blue>
</value>
</parameter>


I tried a program called "editix" but it won't let me change this parameter for all the instances... any help for this problem ? Is there a terminal app that can help me ? Why won't TextEdit Let me do this ?

Thanks for any help !



jiminaus
Jun 11, 2011, 06:42 PM
Based around just the XML you posted, I came up with the following awk program that make the changes.

subtitlecolor.awk

BEGIN {
FS = ""
}

/<parameter>/ {
in_parameter = 1
parameterid_is_textcolor = 0
}

in_parameter && /<parameterid>.*<\/parameterid>/ {
split($0, a, /<\/?parameterid>/)
parameterid_is_textcolor = (a[2] == "textcolor")
}

parameterid_is_textcolor && /<value>/ {
in_value = 1
}

in_value && /<red>235<\/red>/ {
split($0, a, /<red>235<\/red>/)
print a[1] "<red>255</red>" a[2]
next
}

in_value && /<green>235<\/green>/ {
split($0, a, /<green>235<\/green>/)
print a[1] "<green>255</green>" a[2]
next
}

in_value && /<blue>235<\/blue>/ {
split($0, a, /<blue>235<\/blue>/)
print a[1] "<blue>255</blue>" a[2]
next
}

/<\/value>/ {
in_value = 0
}

/<\/parameter>/ {
in_parameter = 0
}

{ print $0 }


You can run the program like so from Terminal.

awk -f subtitlecolor.awk < in.xml > out.xml

Assuming you saved the awk program in subtitlecolor.awk, the FCP xml is in in.xml, both the awk program and FCP xml are in the same directory, and you've changed to that directory in Terminal.

Afterwards you should have a new file called out.xml which has yellow textcolor parameters changed to white textcolor parameters.

Note that it will change all such occurrences. You have given enough XML context to limit it just to the subtitle track(s).

larkost
Jun 12, 2011, 07:01 PM
When you get up to this complexity, then it is time to start learning a scripting language like Python, Ruby, or Perl. My recommendation would be for Python as the xml.dom.minidom class is not too bad (but a little awkward). Perl is a bit worse for xml handling, and someone else is going to have to chime in on Ruby, as I have not used it for xml handling.

A second thought: you might be able to get away with an XSLT transformation, assuming you can express the rule in XSLT.

initialsBB
Jun 13, 2011, 04:59 AM
@jiminaus
Amazing, thank you so much for this piece of knowledge !

I created to AWK and ran it in the terminal. Unfortunately the text is still white, but looking at the code I was wondering if maybe the values you entered are not quite matched. If you wouldn't mind explaining this following bit I can try and adapt it better on my side :


in_value && /<red>235<\/red>/ {
split($0, a, /<red>235<\/red>/)
print a[1] "<red>255</red>" a[2]
next


is the print line that is actually writing the color component value into the XML ?
print a[1] "<red>255</red>" a[2]

If I can read your code, then first block after the BEGIN header looks for the instance where the parameterid is textcolor, the next block loads the parameter and then there are the three print commands for R, G and B...?

@larkost
Much appreciation for the thoughts. As you may know Final Cut Pro X is due out this month and I am not alone in praying these issues have been sorted out. Nevertheless XML sequence exporting is one of the more confidential but incredibly powerful features of the app. I will definitely look into Python when I have some time on my hands.

jiminaus
Jun 13, 2011, 05:59 AM
in_value && /<red>235<\/red>/ {
split($0, a, /<red>235<\/red>/)
print a[1] "<red>255</red>" a[2]
next
}



Let me paraphrase the code.

1) If we're inside a value element (associated with a textcolor parameter), and the line contains <red>235</red>, then do a-c below. If not, skip over a-c.
a) Put everything on the line before <red>235</red> into a[1] and everything after into a[2]
b) Print out a[1], followed by <red>255</red>, followed by a[2]
c) Don't process any more instructions for this line, move on to the next line

a) and b) is just a way of outputting a line, but first replacing <red>235</red> with <red>255</red>.

BTW Awk is not my thing. I do have the re-learn it every time I have to go use it, which isn't very often. So I may not have created the best awk program possible. Having said that though, I did test the code against the sample XML you gave and it did work. When you look at the outputted xml (I called it out.xml in my instructions above), do you see the changed values insides the red, green, and blue tags?

initialsBB
Jun 13, 2011, 06:21 AM
Thank you for the explanation ! I may not have clearly stated my problem but thanks to you here is the code that works :)
(I wanted to go from RGB values 255,255,255 to 255,235,0)


BEGIN {
FS = ""
}

/<parameter>/ {
in_parameter = 1
parameterid_is_textcolor = 0
}

in_parameter && /<parameterid>.*<\/parameterid>/ {
split($0, a, /<\/?parameterid>/)
parameterid_is_textcolor = (a[2] == "textcolor")
}

parameterid_is_textcolor && /<value>/ {
in_value = 1
}

in_value && /<red>255<\/red>/ {
split($0, a, /<red>255<\/red>/)
print a[1] "<red>255</red>" a[2]
next
}

in_value && /<green>255<\/green>/ {
split($0, a, /<green>255<\/green>/)
print a[1] "<green>235</green>" a[2]
next
}

in_value && /<blue>255<\/blue>/ {
split($0, a, /<blue>255<\/blue>/)
print a[1] "<blue>0</blue>" a[2]
next
}

/<\/value>/ {
in_value = 0
}

/<\/parameter>/ {
in_parameter = 0
}

{ print $0 }


This piece of code can now help me batch change the text controls !! :)
If I wanted to change now say the font, I would simply replace the textcolor ID with the relevant font one, cut out the green and blue channel changes and be done... I'll definitely be having oodles of fun with this, and make colleagues green with envy :p

Thank you again !