You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过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, "&", "&amp;")
    set escaped_text to my replace_text(escaped_text, "<", "&lt;")
    set escaped_text to my replace_text(escaped_text, ">", "&gt;")
    set escaped_text to my replace_text(escaped_text, "\"", "&quot;")
    set escaped_text to my replace_text(escaped_text, "'", "&apos;")
    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

关键修改点说明

  1. 调整文件获取逻辑:把原来的get_folder_list改成get_folder_items,返回Finder文件对象而非仅路径,方便后续获取文件属性。
  2. 新增元数据获取函数:通过mdls命令读取系统存储的媒体元数据(比如时长、艺术家、专辑等),这是Mac上获取文件元数据的高效方式。
  3. XML生成逻辑:循环每个文件,拼接XML标签,同时处理特殊字符转义(避免XML格式错误)。
  4. 文件大小格式化:把字节数转换成kb/mb/gb的易读格式。
  5. 时长转换:把秒数转换成分:秒的格式(比如300秒转成5:00)。
  6. 移除原字符串/列表选项:因为现在固定输出XML字符串,所以去掉了return_as_string的相关逻辑,简化流程。

内容的提问来源于stack exchange,提问作者mk117

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:02:17