가끔 파워포인트 파일 여러 개의 내용을 일괄적으로 변경해야 하는 경우가 있다. 이때 하나씩 하다보면 단순 반복 작업에 매우 지치고 귀찮음을 느끼게 된다.
pptx 파일 포맷은 XML 기반의 파일이 압축된 형태이기 때문에, 압축을 풀고 XML을 편집하면 일괄 변경할 수 있다.
주의: 이 글의 작성자는 pptx 파일 포맷에 대한 깊은 이해가 있지 않고, 슬라이드의 단순 링크 변경이 목표이다.
목표: a.pptx
에 있는 모든 http://a.com/
링크를 http://b.net/
로 바꾸는 것
파일 a.pptx
가 있을때, 확장자를 zip으로 변경하면 압축을 풀 수 있고, 내용물을 볼 수 있다.
압축을 해제하니 3개의 폴더 (_rels
, docProps
, ppt
)와 1개의 파일 ([Content_Types].xml
)가 있고, 폴더를 살펴보니 ppt/slides
에 슬라이드 내용이 있는 것을 확인할 수 있다.
K페이지의 내용은 slideK.xml
에 있고, 링크와 관련된 정보는 _rels/slideK.xml.rels
에 있다.
어차피 링크만 바꾸는 것이 목적이기 때문에, XML을 파싱할 필요는 없다. XML 파일을 문자열로 읽고, 문자열 변경을 한 다음 다시 문자열 저장을 했다.
아래 go(f)
는 파일 f
에 들어있는 링크를 변경하는 함수이다. 파일 f
의 파일명을 temp.zip
으로 바꾸고, temp/
에 압축을 푼다. 그 다음 적절한 처리를 하고 다시 temp.zip
으로 압축한다. 마지막으로 파일명을 다시 f
로 변경한다.
def go(f): # pptx -> zip f_zip = 'temp.zip' os.rename(f, f_zip) # unzip os.system('unzip -q -d temp %s' % f_zip) os.system('rm %s' % f_zip) find_xml() # zip again os.system('cd temp; zip -q -r9 ../%s *' % f_zip) os.system('rm -rf temp') # zip -> pptx os.rename(f_zip, f)
find_xml()
은 ppt/slides/slideK.xml
, ppt/slides/_rels/slideK.xml.rels
를 모두 찾는다.
def find_xml(): slide_folder = 'temp/ppt/slides/' for f,d,files in os.walk(slide_folder): for fname in files: if '.xml' not in fname: continue print (f, d, fname) xml_file = os.path.join(f, fname) convert(xml_file)
convert(xml_file)
은 XML 파일 xml_file
에 있는 모든 링크를 원하는대로 변경하는 함수이다.
def convert(xml_file): with open(xml_file, 'r') as fp: s = fp.read() s = s.replace('http://a.com/', 'http://b.net/') with open(xml_file, 'w') as fp: fp.write(s)
좀 더 섬세한 작업을 하려면 XML을 파싱하거나 정규 표현식을 사용하면 될 것 같다. XML을 파싱하면 배경 색상 변경, 폰트 변경, 문단 설정 변경 등도 할 수 있지만, 현재는 그런 작업은 필요가 없어서 해보지 않았다.