如何通过AppleScript将文件路径列表转为带属性的XML格式?
需求:修改AppleScript生成XML格式的媒体文件属性列表
嘿,我这儿有个AppleScript脚本,本来是临时替代Whereisit用的,能把文件夹里的文件路径列表(换行分隔)复制到剪贴板。但现在我想把它改成输出XML格式的内容,要包含文件名、文件路径、音轨时长、文件大小、艺术家、曲目名、专辑名这些属性。
期望的XML示例格式
<items> <item> <filename>file1.mp3</filename> <filepath>/path/to/the/file/</filepath> <tracklength>3:00</tracklength> <filesize>6mb</filesize> <artist>artist name</artist> <title>Song Title</title> <album>Album Name</album> </item> </items>
原AppleScript脚本
property script_name : "List Folder Contents" property script_description : "This script will list a folder's contents returning full paths as strings and limit the list to specific file types. The script can also process subfolders (recursion)." set the_folder to (choose folder with prompt "Choose a Folder to List:") as Unicode text set file_types to {} --file types, set to {} and inc_folders to true to just return folders; file types are 4 character codes such as "osas" or "TEXT" set with_subfolders to my get_boolean("Search subfolders?", {"No", "Yes"}) if with_subfolders = "user cancelled" then return set inc_folders to my get_boolean("Include folders in the list? (If you only want file names, and not folder names, select \"No\".)", {"No", "Yes"}) if inc_folders = "user cancelled" then return set use_posix_path to my get_boolean("Return the paths as HFS (Mac-style) or POSIX (UNIX-style)?", {"HFS", "POSIX"}) if use_posix_path = "user cancelled" then return set return_as_string to my get_boolean("Return the results as an AppleScript list or a string with each file on its own line?", {"List", "String"}) if return_as_string = "user cancelled" then return set add_to_clipboard to my get_boolean("Copy the results to the clipboard?", {"No", "Yes"}) if add_to_clipboard = "user cancelled" then return set the_files to get_folder_list(the_folder, file_types, with_subfolders, inc_folders, use_posix_path) if return_as_string then tell (a reference to my text item delimiters) set {old_tid, contents} to {contents, return} set {the_files_string, contents} to {the_files as Unicode text, old_tid} end tell copy the_files_string to the_files end if if add_to_clipboard then if not return_as_string then copy the_files to the_files_string repeat with i from 1 to (count the_files_string) set item i of the_files_string to ("\"" & item i of the_files_string & "\", ") end repeat set the_files_string to ("{" & (text 1 thru -3 of (the_files_string as Unicode text)) & "}") end if set the clipboard to the_files_string end if beep return the_files on get_folder_list(the_folder, file_types, with_subfolders, inc_folders, use_posix_path) set the_files to {} tell application "Finder" to set folder_list to items of folder the_folder repeat with new_file in folder_list try set temp_file_type to file type of new_file on error set temp_file_type to "fold" end try if file_types contains temp_file_type or file_types = {} then if use_posix_path then set the_files to the_files & {POSIX path of (new_file as Unicode text)} else set the_files to the_files & {new_file as Unicode text} end if end if if temp_file_type = "fold" then if inc_folders and file_types ≠ {} then if use_posix_path then set the_files to the_files & {POSIX path of (new_file as Unicode text)} else set the_files to the_files & {new_file as Unicode text} end if end if if with_subfolders then set the_files to the_files & my get_folder_list((new_file as Unicode text), file_types, with_subfolders, inc_folders, use_posix_path) end if end repeat return the_files end get_folder_list on get_boolean(m, b) try return (button returned of (display dialog m buttons ({"Cancel"} & b) default button 3 with icon 1) = (b's item 2)) on error return "user cancelled" end try end get_boolean
我是AppleScript新手,不确定该怎么修改上面的脚本实现XML输出。我推测可能需要修改if add_to_clipboard then代码块里的以下语句:
set item i of the_files_string to ("\"" & item i of the_files_string & "\", ")set the_files_string to ("{" & (text 1 thru -3 of (the_files_string as Unicode text)) & "}")
修改后的完整脚本
property script_name : "List Folder Contents as XML" property script_description : "This script will list a folder's contents returning XML with media metadata and limit the list to specific file types. The script can also process subfolders (recursion)." set the_folder to (choose folder with prompt "Choose a Folder to List:") as Unicode text set file_types to {} --file types, set to {} and inc_folders to true to just return folders; file types are 4 character codes such as "osas" or "TEXT" set with_subfolders to my get_boolean("Search subfolders?", {"No", "Yes"}) if with_subfolders = "user cancelled" then return set inc_folders to my get_boolean("Include folders in the list? (If you only want file names, and not folder names, select \"No\".)", {"No", "Yes"}) if inc_folders = "user cancelled" then return set use_posix_path to my get_boolean("Return the paths as HFS (Mac-style) or POSIX (UNIX-style)?", {"HFS", "POSIX"}) if use_posix_path = "user cancelled" then return set add_to_clipboard to my get_boolean("Copy the XML results to the clipboard?", {"No", "Yes"}) if add_to_clipboard = "user cancelled" then return -- 获取文件列表(包含完整Finder项,而非仅路径) set the_files to get_folder_items(the_folder, file_types, with_subfolders, inc_folders) -- 生成XML内容 set xml_content to "<items>" & return repeat with a_file in the_files -- 获取文件基本信息 tell application "Finder" set file_name to name of a_file set file_path to POSIX path of (a_file as Unicode text) set file_size to size of a_file -- 转换文件大小为易读格式 set readable_size to my format_file_size(file_size) end tell -- 获取媒体元数据(使用mdls命令) set track_length to my get_metadata(POSIX path of (a_file as Unicode text), "kMDItemDurationSeconds") set artist to my get_metadata(POSIX path of (a_file as Unicode text), "kMDItemAuthors") set title to my get_metadata(POSIX path of (a_file as Unicode text), "kMDItemDisplayName") set album to my get_metadata(POSIX path of (a_file as Unicode text), "kMDItemAlbum") -- 处理时长格式(秒转分:秒) if track_length is not "" then set total_seconds to track_length as number set minutes to total_seconds div 60 set seconds to total_seconds mod 60 set track_length_string to (minutes as string) & ":" & text -2 thru -1 of ("0" & (seconds as string)) else set track_length_string to "" end if -- 拼接单个item的XML set xml_content to xml_content & " <item>" & return set xml_content to xml_content & " <filename>" & my escape_xml(file_name) & "</filename>" & return set xml_content to xml_content & " <filepath>" & my escape_xml(file_path) & "</filepath>" & return set xml_content to xml_content & " <tracklength>" & track_length_string & "</tracklength>" & return set xml_content to xml_content & " <filesize>" & readable_size & "</filesize>" & return set xml_content to xml_content & " <artist>" & my escape_xml(artist) & "</artist>" & return set xml_content to xml_content & " <title>" & my escape_xml(title) & "</title>" & return set xml_content to xml_content & " <album>" & my escape_xml(album) & "</album>" & return set xml_content to xml_content & " </item>" & return end repeat set xml_content to xml_content & "</items>" -- 复制到剪贴板并提示 if add_to_clipboard then set the clipboard to xml_content display dialog "XML内容已复制到剪贴板!" buttons {"OK"} default button 1 with icon 1 end if beep return xml_content -- 辅助函数:获取文件夹中的Finder项(而非仅路径) on get_folder_items(the_folder, file_types, with_subfolders, inc_folders) set the_items to {} tell application "Finder" to set folder_list to items of folder the_folder repeat with new_item in folder_list try set temp_file_type to file type of new_item on error set temp_file_type to "fold" end try -- 判断是否要包含当前项 if (file_types contains temp_file_type or file_types = {}) and not (temp_file_type = "fold" and not inc_folders) then set the_items to the_items & {new_item} end if -- 递归处理子文件夹 if temp_file_type = "fold" and with_subfolders then set the_items to the_items & my get_folder_items((new_item as Unicode text), file_types, with_subfolders, inc_folders) end if end repeat return the_items end get_folder_items -- 辅助函数:获取文件元数据(使用mdls命令) on get_metadata(file_path, metadata_key) try set metadata_result to do shell script "mdls -raw -name " & quoted form of metadata_key & " " & quoted form of file_path -- 处理数组类型的元数据(比如艺术家可能是数组) if metadata_result starts with "(" then set metadata_result to text 2 thru -2 of metadata_result set AppleScript's text item delimiters to ", " set metadata_result to text items of metadata_result set AppleScript's text item delimiters to ", " set metadata_result to metadata_result as string end if return metadata_result on error return "" end try end get_metadata -- 辅助函数:格式化文件大小为易读格式 on format_file_size(size_in_bytes) if size_in_bytes < 1024 then return (size_in_bytes as string) & "b" else if size_in_bytes < 1048576 then return (round (size_in_bytes / 1024) rounding to nearest) as string & "kb" else if size_in_bytes < 1073741824 then return (round (size_in_bytes / 1048576) rounding to nearest) as string & "mb" else return (round (size_in_bytes / 1073741824) rounding to nearest) as string & "gb" end if end format_file_size -- 辅助函数:转义XML特殊字符 on escape_xml(text_to_escape) set escaped_text to text_to_escape set escaped_text to my replace_text(escaped_text, "&", "&") set escaped_text to my replace_text(escaped_text, "<", "<") set escaped_text to my replace_text(escaped_text, ">", ">") set escaped_text to my replace_text(escaped_text, "\"", """) set escaped_text to my replace_text(escaped_text, "'", "'") return escaped_text end escape_xml -- 辅助函数:字符串替换 on replace_text(source_text, find_text, replace_text) set AppleScript's text item delimiters to find_text set text_items to text items of source_text set AppleScript's text item delimiters to replace_text return text_items as string end replace_text on get_boolean(m, b) try return (button returned of (display dialog m buttons ({"Cancel"} & b) default button 3 with icon 1) = (b's item 2)) on error return "user cancelled" end try end get_boolean
关键修改点说明
- 调整文件获取逻辑:把原来的
get_folder_list改成get_folder_items,返回Finder文件对象而非仅路径,方便后续获取文件属性。 - 新增元数据获取函数:通过
mdls命令读取系统存储的媒体元数据(比如时长、艺术家、专辑等),这是Mac上获取文件元数据的高效方式。 - XML生成逻辑:循环每个文件,拼接XML标签,同时处理特殊字符转义(避免XML格式错误)。
- 文件大小格式化:把字节数转换成kb/mb/gb的易读格式。
- 时长转换:把秒数转换成
分:秒的格式(比如300秒转成5:00)。 - 移除原字符串/列表选项:因为现在固定输出XML字符串,所以去掉了
return_as_string的相关逻辑,简化流程。
内容的提问来源于stack exchange,提问作者mk117
相关产品推荐
相关产品推荐

