0

EDIT #2

@CJK and @mockman

so using both your ideas I've created this god awful long script that does the trick for the first offset value in the xml and first marker value shown in the xml

Now the goal would be to see how run or loop these handlers to get every Marker's start value and replace it with every asset-clip's offset value.

Example:

<spine>
                        <asset-clip ref="r2" offset="0s" name="against-gravity_by_evgeny-bardyuzha_Artlist" start="86400s" duration="3866100/352800s" audioRole="dialogue">
                            <asset-clip ref="r3" lane="1" offset="6489053/3200s" name="Pexels Videos 1730395" duration="2s" format="r4" tcFormat="NDF" audioRole="dialogue">
                                <conform-rate srcFrameRate="25"/>
                            </asset-clip>
                            <asset-clip ref="r5" lane="1" offset="1036856/12s" name="production ID_4882341" start="554/25s" duration="661500/352800s" format="r6" tcFormat="NDF">
                                <conform-rate srcFrameRate="25"/>
                            </asset-clip>
                            <marker start="276489053/3200s" duration="1/48000s" value="Marker 1"/>
                            <marker start="6912372957/80000s" duration="1/48000s" value="Marker 2"/>
                            <marker start="31106358853/360000s" duration="1/48000s" value="Marker 3"/>
                            <marker start="10369005107/120000s" duration="1/48000s" value="Marker 4"/>
                            <marker start="1244307173/14400s" duration="1/48000s" value="Marker 5"/>
                        </asset-clip>
                    </spine>

AFTER RUNNING SCRIPT the desired Results below>>> Notice that the offset values match the markers values

<spine>
                        <asset-clip ref="r2" offset="276489053/3200s" name="against-gravity_by_evgeny-bardyuzha_Artlist" start="86400s" duration="3866100/352800s" audioRole="dialogue">
                            <asset-clip ref="r3" lane="1" offset="6912372957/80000s" name="Pexels Videos 1730395" duration="2s" format="r4" tcFormat="NDF" audioRole="dialogue">
                                <conform-rate srcFrameRate="25"/>
                            </asset-clip>
                            <asset-clip ref="r5" lane="1" offset="31106358853/360000s" name="production ID_4882341" start="554/25s" duration="661500/352800s" format="r6" tcFormat="NDF">
                                <conform-rate srcFrameRate="25"/>
                            </asset-clip>
                            <marker start="276489053/3200s" duration="1/48000s" value="Marker 1"/>
                            <marker start="6912372957/80000s" duration="1/48000s" value="Marker 2"/>
                            <marker start="31106358853/360000s" duration="1/48000s" value="Marker 3"/>
                            
{Hoping the Script ignores this line because no other </asset-clip> exists to change}
<marker start="10369005107/120000s" duration="1/48000s" value="Marker 4"/ > 
{Hoping the Script ignores this line because no other </asset-clip> exists to change}                            
<marker start="1244307173/14400s" duration="1/48000s" value="Marker 5"/>
                        </asset-clip>
                    </spine>

Here's the entire fcpxml in it's raw complete format:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE fcpxml>

<fcpxml version="1.9">
    <resources>
        <format id="r1" name="FFVideoFormat1080p24" frameDuration="100/2400s" width="1920" height="1080" colorSpace="1-1-1 (Rec. 709)"/>
        <asset id="r2" name="against-gravity_by_evgeny-bardyuzha_Artlist" uid="B1689FB76C9E4A9AF0298680A873E1D2" start="86400s" duration="6297088/44100s" hasAudio="1" audioSources="1" audioChannels="2" audioRate="44100">
            <media-rep kind="original-media" sig="B1689FB76C9E4A9AF0298680A873E1D2" src="file:///Users/davesmacpro/Music/Music%20for%20Projects/against-gravity_by_evgeny-bardyuzha_Artlist.wav">
                <bookmark>Ym9vaxQDAAAAAAQQMAAAAHi61zvH+Xt9eDtxi789DbINi+KCtO1mu9FKykYF+ptlEAIAAAQAAAADAwAAABgAKAUAAAABAQAAVXNlcnMAAAALAAAAAQEAAGRhdmVzbWFjcHJvAAUAAAABAQAATXVzaWMAAAASAAAAAQEAAE11c2ljIGZvciBQcm9qZWN0cwAALwAAAAEBAABhZ2FpbnN0LWdyYXZpdHlfYnlfZXZnZW55LWJhcmR5dXpoYV9BcnRsaXN0LndhdgAUAAAAAQYAABAAAAAgAAAANAAAAEQAAABgAAAACAAAAAQDAABPUwAAAAAAAAgAAAAEAwAAT0AHAAAAAAAIAAAABAMAAEm4BwAAAAAACAAAAAQDAAAPyQcAAAAAAAgAAAAEAwAAN8kHAAAAAAAUAAAAAQYAALQAAADEAAAA1AAAAOQAAAD0AAAACAAAAAAEAABBwaczlkwtyRgAAAABAgAAAQAAAAAAAAAPAAAAAAAAAAAAAAAAAAAACAAAAAQDAAADAAAAAAAAAAQAAAADAwAA9QEAAAgAAAABCQAAZmlsZTovLy8MAAAAAQEAAE1hY2ludG9zaCBIRAgAAAAEAwAAABDQ2e0BAAAIAAAAAAQAAEHEhebagAAAJAAAAAEBAAAxQTAwQjhEMi0zNjIwLTQxQTEtODA0OC02NzBCQUI1ODRFM0MYAAAAAQIAAIEAAAABAAAA7xMAAAEAAAAAAAAAAAAAAAEAAAABAQAALwAAAAAAAAABBQAAzAAAAP7///8BAAAAAAAAABAAAAAEEAAAmAAAAAAAAAAFEAAABAEAAAAAAAAQEAAAMAEAAAAAAABAEAAAIAEAAAAAAAACIAAA/AEAAAAAAAAFIAAAbAEAAAAAAAAQIAAAfAEAAAAAAAARIAAAsAEAAAAAAAASIAAAkAEAAAAAAAATIAAAoAEAAAAAAAAgIAAA3AEAAAAAAAAwIAAACAIAAAAAAAABwAAAUAEAAAAAAAARwAAAIAAAAAAAAAASwAAAYAEAAAAAAAAQ0AAABAAAAAAAAAA=</bookmark>
            </media-rep>
            <metadata>
                <md key="com.apple.proapps.mio.ingestDate" value="2022-12-12 02:32:50 -1000"/>
            </metadata>
        </asset>
        <asset id="r3" name="Pexels Videos 1730395" uid="9E54D5C8D17577E244F9F7835F3A278F" start="0s" duration="36144/600s" hasVideo="1" format="r4" hasAudio="1" videoSources="1" audioSources="1" audioChannels="2" audioRate="48000">
            <media-rep kind="original-media" sig="9E54D5C8D17577E244F9F7835F3A278F" src="file:///Users/davesmacpro/Movies/Pexels%20Videos%201730395.mp4">
                <bookmark>Ym9va8wCAAAAAAQQMAAAAHLUxWFmj8UGU72GTMAnlCWB/KtAonN8I+RDCiLsmrssyAEAAAQAAAADAwAAABgAKAUAAAABAQAAVXNlcnMAAAALAAAAAQEAAGRhdmVzbWFjcHJvAAYAAAABAQAATW92aWVzAAAZAAAAAQEAAFBleGVscyBWaWRlb3MgMTczMDM5NS5tcDQAAAAQAAAAAQYAABAAAAAgAAAANAAAAEQAAAAIAAAABAMAAE9TAAAAAAAACAAAAAQDAABPQAcAAAAAAAgAAAAEAwAAxRp+AAAAAAAIAAAABAMAADzrPQAAAAAAEAAAAAEGAACAAAAAkAAAAKAAAACwAAAACAAAAAAEAABBwpXm0YAAABgAAAABAgAAAQAAAAAAAAAPAAAAAAAAAAAAAAAAAAAACAAAAAQDAAACAAAAAAAAAAQAAAADAwAA9QEAAAgAAAABCQAAZmlsZTovLy8MAAAAAQEAAE1hY2ludG9zaCBIRAgAAAAEAwAAABDQ2e0BAAAIAAAAAAQAAEHEhebagAAAJAAAAAEBAAAxQTAwQjhEMi0zNjIwLTQxQTEtODA0OC02NzBCQUI1ODRFM0MYAAAAAQIAAIEAAAABAAAA7xMAAAEAAAAAAAAAAAAAAAEAAAABAQAALwAAAAAAAAABBQAAzAAAAP7///8BAAAAAAAAABAAAAAEEAAAaAAAAAAAAAAFEAAAwAAAAAAAAAAQEAAA6AAAAAAAAABAEAAA2AAAAAAAAAACIAAAtAEAAAAAAAAFIAAAJAEAAAAAAAAQIAAANAEAAAAAAAARIAAAaAEAAAAAAAASIAAASAEAAAAAAAATIAAAWAEAAAAAAAAgIAAAlAEAAAAAAAAwIAAAwAEAAAAAAAABwAAACAEAAAAAAAARwAAAIAAAAAAAAAASwAAAGAEAAAAAAAAQ0AAABAAAAAAAAAA=</bookmark>
            </media-rep>
            <metadata>
                <md key="com.apple.proapps.studio.rawToLogConversion" value="0"/>
                <md key="com.apple.proapps.spotlight.kMDItemProfileName" value="HD (1-1-1)"/>
                <md key="com.apple.proapps.studio.cameraISO" value="0"/>
                <md key="com.apple.proapps.studio.cameraColorTemperature" value="0"/>
                <md key="com.apple.proapps.spotlight.kMDItemCodecs">
                    <array>
                        <string>AVC Coding</string>
                        <string>MPEG-4 AAC</string>
                    </array>
                </md>
                <md key="com.apple.proapps.mio.ingestDate" value="2022-12-09 10:31:28 -1000"/>
            </metadata>
        </asset>
        <format id="r4" name="FFVideoFormat3840x2160p25" frameDuration="100/2500s" width="3840" height="2160" colorSpace="1-1-1 (Rec. 709)"/>
        <asset id="r5" name="production ID_4882341" uid="6F199E9ADD1C3E1C25A01431E12EF3E3" start="0s" duration="1943/25s" hasVideo="1" format="r6" videoSources="1">
            <media-rep kind="original-media" sig="6F199E9ADD1C3E1C25A01431E12EF3E3" src="file:///Users/davesmacpro/Movies/production%20ID_4882341.mp4">
                <bookmark>Ym9va8wCAAAAAAQQMAAAAELPIBuUH6inb74/CLc27nr2yrwiIVd8Ni9hDXz1lgueyAEAAAQAAAADAwAAABgAKAUAAAABAQAAVXNlcnMAAAALAAAAAQEAAGRhdmVzbWFjcHJvAAYAAAABAQAATW92aWVzAAAZAAAAAQEAAHByb2R1Y3Rpb24gSURfNDg4MjM0MS5tcDQAAAAQAAAAAQYAABAAAAAgAAAANAAAAEQAAAAIAAAABAMAAE9TAAAAAAAACAAAAAQDAABPQAcAAAAAAAgAAAAEAwAAxRp+AAAAAAAIAAAABAMAAFvrPQAAAAAAEAAAAAEGAACAAAAAkAAAAKAAAACwAAAACAAAAAAEAABBwpXn7AAAABgAAAABAgAAAQAAAAAAAAAPAAAAAAAAAAAAAAAAAAAACAAAAAQDAAACAAAAAAAAAAQAAAADAwAA9QEAAAgAAAABCQAAZmlsZTovLy8MAAAAAQEAAE1hY2ludG9zaCBIRAgAAAAEAwAAABDQ2e0BAAAIAAAAAAQAAEHEhebagAAAJAAAAAEBAAAxQTAwQjhEMi0zNjIwLTQxQTEtODA0OC02NzBCQUI1ODRFM0MYAAAAAQIAAIEAAAABAAAA7xMAAAEAAAAAAAAAAAAAAAEAAAABAQAALwAAAAAAAAABBQAAzAAAAP7///8BAAAAAAAAABAAAAAEEAAAaAAAAAAAAAAFEAAAwAAAAAAAAAAQEAAA6AAAAAAAAABAEAAA2AAAAAAAAAACIAAAtAEAAAAAAAAFIAAAJAEAAAAAAAAQIAAANAEAAAAAAAARIAAAaAEAAAAAAAASIAAASAEAAAAAAAATIAAAWAEAAAAAAAAgIAAAlAEAAAAAAAAwIAAAwAEAAAAAAAABwAAACAEAAAAAAAARwAAAIAAAAAAAAAASwAAAGAEAAAAAAAAQ0AAABAAAAAAAAAA=</bookmark>
            </media-rep>
            <metadata>
                <md key="com.apple.proapps.studio.rawToLogConversion" value="0"/>
                <md key="com.apple.proapps.spotlight.kMDItemProfileName" value="HD (1-1-1)"/>
                <md key="com.apple.proapps.studio.cameraISO" value="0"/>
                <md key="com.apple.proapps.studio.cameraColorTemperature" value="0"/>
                <md key="com.apple.proapps.spotlight.kMDItemCodecs">
                    <array>
                        <string>AVC Coding</string>
                    </array>
                </md>
                <md key="com.apple.proapps.mio.ingestDate" value="2022-12-09 10:31:28 -1000"/>
            </metadata>
        </asset>
        <format id="r6" name="FFVideoFormat4096x2160p25" frameDuration="100/2500s" width="4096" height="2160" colorSpace="1-1-1 (Rec. 709)"/>
    </resources>
    <library location="file:///Users/davesmacpro/Desktop/XML%20tests/Test%20project%20for%20xml.fcpbundle/">
        <event name="12-9-22" uid="A11C4F20-CFCC-4D32-9B9C-AABF1829B666">
            <project name="24 p test rewrite file" uid="717DAFEC-AB91-403C-A451-9E4CC8EC35E8" modDate="2022-12-16 18:04:54 -1000">
                <sequence format="r1" duration="26300/2400s" tcStart="0s" tcFormat="NDF" audioLayout="stereo" audioRate="48k">
                    <spine>
                        <asset-clip ref="r2" offset="0s" name="against-gravity_by_evgeny-bardyuzha_Artlist" start="86400s" duration="3866100/352800s" audioRole="dialogue">
                            <asset-clip ref="r3" lane="1" offset="3800/3200s" name="Pexels Videos 1730395" duration="2s" format="r4" tcFormat="NDF" audioRole="dialogue">
                                <conform-rate srcFrameRate="25"/>
                            </asset-clip>
                            <asset-clip ref="r5" lane="1" offset="1036856/12s" name="production ID_4882341" start="554/25s" duration="661500/352800s" format="r6" tcFormat="NDF">
                                <conform-rate srcFrameRate="25"/>
                            </asset-clip>
                            <marker start="276489053/3200s" duration="1/48000s" value="Marker 1"/>
                            <marker start="6912372957/80000s" duration="1/48000s" value="Marker 2"/>
                            <marker start="31106358853/360000s" duration="1/48000s" value="Marker 3"/>
                            <marker start="10369005107/120000s" duration="1/48000s" value="Marker 4"/>
                            <marker start="1244307173/14400s" duration="1/48000s" value="Marker 5"/>
                        </asset-clip>
                    </spine>
                </sequence>
            </project>
        </event>
        <smart-collection name="Projects" match="all">
            <match-clip rule="is" type="project"/>
        </smart-collection>
        <smart-collection name="All Video" match="any">
            <match-media rule="is" type="videoOnly"/>
            <match-media rule="is" type="videoWithAudio"/>
        </smart-collection>
        <smart-collection name="Audio Only" match="all">
            <match-media rule="is" type="audioOnly"/>
        </smart-collection>
        <smart-collection name="Stills" match="all">
            <match-media rule="is" type="stills"/>
        </smart-collection>
        <smart-collection name="Favorites" match="all">
            <match-ratings value="favorites"/>
        </smart-collection>
    </library>
</fcpxml>

Only need to just focus changes on the:

spine "data to manipulate section" spine area

2 Answers 2

0

There are probably a couple of approaches you could take but here is one that should solve the specific problem here.

use scripting additions
set tf to choose file with prompt "Choose a File" of type {"fcpxml", "xml"}
tell application "Finder" to set tf2 to duplicate tf
set textBlob to read file (tf2 as text)

-- offsets to find and their lengths
set badStr to "offset="
set badLen to (length of badStr) + 1 -- i.e. 8
set goodStr to "<marker start="
set goodLen to (length of goodStr) + 1 -- i.e. 15

-- textSpan begins as copy of source text but will be reduced
set textSpan to text 1 thru -1 of textBlob

-- find offset and string to replace
set boffsetLft to (get offset of badStr in textSpan) + badLen
set textSpan to text boffsetLft thru -1 of textSpan
set boffsetRgt to (get offset of space in textSpan) - 2
set badFound to text boffsetLft thru (boffsetLft + boffsetRgt - 1) of textBlob
--> "1234/3200s"

-- find offset and string to substitute
set goffsetLft to (get offset of goodStr in textSpan) + goodLen
set textSpan to text goffsetLft thru -1 of textSpan
set goffsetRgt to (get offset of space in textSpan) - 2
set goodReplace to text 1 thru goffsetRgt of textSpan
--> "276489053/3200s"

set AppleScript's text item delimiters to badFound
set newTextBlob to text items of textBlob
set AppleScript's text item delimiters to goodReplace
set newTextBlob to newTextBlob as text

The script lets the user choose a file, which it duplicates, and then reads in that duplicate. It begins with 'use scripting additions' because the offset command is one and occasionally there is flaky behaviour with it.

Next, it assigns the two search strings to variables along with their functional lengths. This combination will be used to set the bookend offsets for the desired strings.

A second variable is used to provide a reducible copy of the text which will simplify things.

Next, the 'offset' string (badFound) will be located. Its left end by finding the offset of 'offset=' and then specifying the first character after the quote. The right end by finding the first space after and then the last character before the quote. The same is then done for the replacement string (goodFound). Both results are assigned to variables.

Finally, the entire text is split using badFound as the text delimiter and then reformed around goodFound. In your example, the first 'asset clip' line would begin like this below while the remainder of the text would be unchanged:

<asset-clip ref="r3" lane="1" offset="6912372957/80000s"

At this point, you can save the text or do whatever.

2
  • this is a wonderful answer to the problem and the end goal would be to put this into a repeat statement of sorts that could find each marker value (could be 50 or more) and replace each asset clip's offset value to each individual marker value. --see edit
    – wdavtv
    Commented Dec 20, 2022 at 23:19
  • Well, good luck.
    – Mockman
    Commented Dec 21, 2022 at 11:00
0

If you have an XML file, it's usually advisable to parse it as XML rather than as plain text. System Events offers a set of a commands that can descend an XML object hierarchy, and extract the attributes associated with each element.

The XML snippet you provided isn't actually valid XML, as it contains an extraneous </asset-clip> element. So, in order to demonstrate the parsing of your XML snippet, I've removed the first of the two closing </asset-clip> tags:

tell application id "com.apple.SystemEvents"
        set xml to make new XML data with data "<spine>
        <asset-clip ref=\"r3\" lane=\"1\" offset=\"86400s\" 
                    name=\"Pexels Videos 1730395\" 
                    duration=\"646800/352800s\" 
                    format=\"r4\" tcFormat=\"NDF\" 
                    audioRole=\"dialogue\">
                <conform-rate srcFrameRate=\"25\"/>
                <marker start=\"6912372957/80000s\" 
                        duration=\"1/48000s\" 
                        value=\"Marker 2\"/>
        </asset-clip>
</spine>"
        
        tell xml's XML element "spine" to tell ¬
                XML element "asset-clip" to tell ¬
                XML element "marker" to get the ¬
                value of XML attribute "start"
end tell

This returns the expected value "6912372957/80000s".

Since you'll be reading the XML from an XML file rather than a string as I did above, you would start by replacing the line of code in the above script that starts:

set xml to ...

(including the XML string that is split over several lines) with:

set xml to XML element 1 of XML file "/path/to/file.xml"

XML element 1 represents the root element, which is always the starting point when traversing an XML hierarchy. In the XML string I assigned to the variable xml in the above AppleScript code, the root element was the named XML element "spine", but if this is, itself, a child of some other ascendant XML element in your file, then it won't be the root element.

You'll need to construct the AppleScript reference chain that takes System Events's XML parser from XML element 1 (the root element, which is absolutely fine to reference by the index number 1 instead of its name) down through the XML object model to the XML element "spine", from where my code takes it the rest of the way (unless the extraneous </asset-clip> tag isn't, in fact, extraneous in the context of the file as a whole, which will need to be reflected in the AppleScript XML element chain.

My explanation probably makes it sound more difficult than it is in practice, and if you use my AppleScript code as a guide, you can see it's pretty straightforward, and also results in fewer lines of code—that is also going to do a more reliable job—compared to any attempt to parse the XML file as text.


In the same manner we read the start attribute of the <marker> tag, we can also assign a new value to the offset attribute of the <asset-clip> tag.

Where AppleScript was instructed to:

get the value of XML attribute "start"

you would assign this value to a variable, then:

set the value of XML attribute "offset" to ...

You will, of course, need to target the XML element "asset-clip" in the same hierarchical manner as was done for XML element "marker". But that doesn't entail any additional work, and what you end up with is a script that literally does what needs to be done: that is to say, it finds the value of some specific attribute, and uses it to replace the existing value of some other specific attribute. It's two operations.


However, there's a final, third operation. The XML containing the new value for the offset attribute will be stored in the xml variable, through which everything else is referenced. This needs to be written out to file.

A text representation of the XML can be obtained by way of xml's text.

To avoid data loss, I'd advise writing out the XML text to a separate file, then replacing the old file once you validate the new one. In fact, your original approach was sensible, namely duplicating the XML file before reading from it, which you can simply overwrite with the new contents without too much worry.

Duplicating has to be done via Finder:

tell application id "com.apple.finder" to duplicate ¬
        the file ("/path/to/file.xml" as POSIX file) ¬
        to ("/path/to/newfile.xml" as POSIX file)

Writing out is done like so:

tell application id ("com.apple.SystemEvents")
                  .
                  .
        (* all the code to get and replace
           the attributes's values *)
                  .
                  .
        set xmlText to the xml's text
end tell

set the eof of "/path/to/newfile.xml" to 0 --> scrubs the file
write the xmlText as "utf8" to "/path/to/newfile.xml"
1
  • thanks CJK this is indeed very close to what I'm looking for and yes I just wrote out a quick xml demo and didn't format it properly. Great catch! I've edited the post (once again) using ideas from both you and @mockman and now just looking to figure out a way I can repeat this throughout the entire file. Thanks again and sorry this is so time consuming for everyone. You guys are the best!
    – wdavtv
    Commented Dec 21, 2022 at 4:20

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .