Skip to content

Instantly share code, notes, and snippets.

@alainpannetier
Created September 13, 2024 13:18
Show Gist options
  • Save alainpannetier/751843fa378bd999b990df952a253222 to your computer and use it in GitHub Desktop.
Save alainpannetier/751843fa378bd999b990df952a253222 to your computer and use it in GitHub Desktop.
Dirty hacks to check and reset (rebase) the Powerpoint Slide-Ids (sldIds) from 256 onwards in a given pptx presentation.
#!/usr/bin/env python3
import argparse
import traceback
from io import BytesIO
from zipfile import ZipFile, ZIP_DEFLATED
import lxml.etree as ET
xslt_src = """<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main"
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
>
<xsl:output method="xml" />
<xsl:strip-space elements="*"/>
<xsl:key name="mapping" match="/p:presentation/p:sldIdLst/p:sldId" use="@id"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/p:presentation/p:sldIdLst/p:sldId">
<p:sldId id="{256 + count(key('mapping', @id)/preceding-sibling::*)}" r:id="{@r:id}"/>
</xsl:template>
<!-- reuse same new ids in sections -->
<xsl:template match="*[local-name()='sldId' and not (name()=p:sldId)]">
<p:sldId id="{256 + count(key('mapping', @id)/preceding-sibling::*)}"/>
</xsl:template>
</xsl:stylesheet>"""
def parse_arguments():
"""
Purpose: parse and return all arguments
"""
parser = argparse.ArgumentParser(
description='Extracts slide Ids from a pptx Powerpoint presentation'
)
parser.add_argument('-i', '--input', help='Powerpoint input file', dest='input', required=True)
parser.add_argument('-o', '--output', help='Powerpoint output file', dest='output', required=True)
return parser.parse_args()
def read_zip(file_name):
bio = BytesIO(open(file_name, 'rb').read())
archive = ZipFile(bio, 'r')
content = {n: archive.read(n) for n in archive.namelist()}
archive.close()
return content
def write_zip(file_name, content):
bio = BytesIO()
archive = ZipFile(bio, 'w', ZIP_DEFLATED)
for name, data in content.items():
archive.writestr(name, data)
archive.close()
open(file_name, 'wb').write(bio.getvalue())
def reset_slide_ids(content):
input_dom = ET.fromstring(content['ppt/presentation.xml'])
transformer = ET.XSLT(ET.fromstring(xslt_src))
content['ppt/presentation.xml'] = ET.tostring(transformer(input_dom), encoding='utf-8')
return content
def main():
"""
The main sequence of calls
:return:
"""
try:
args = parse_arguments()
except Exception:
print("Error parsing command line")
traceback.print_exc()
return
try:
write_zip(args.output, reset_slide_ids(read_zip(args.input)))
except Exception:
print("Error rewriting zipfile")
traceback.print_exc()
return
if __name__ == "__main__":
main()
#!/usr/bin/env python3
import argparse
import traceback
from io import BytesIO
from zipfile import ZipFile
import lxml.etree as ET
xslt_src = """<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main">
<xsl:output method="text" />
<xsl:strip-space elements="*"/>
<xsl:template match="/p:presentation/p:sldIdLst/p:sldId"><xsl:value-of select="@id"/> - <xsl:value-of select="2147483647 - @id"/> Ids left.<xsl:text>&#10;</xsl:text></xsl:template>
</xsl:stylesheet>"""
def parse_arguments():
"""
Purpose: parse and return all arguments
"""
parser = argparse.ArgumentParser(
description='Extracts slide Ids from a pptx Powerpoint presentation'
)
parser.add_argument('-p', '--pptx', help='Powerpoint input file', dest='pptx', required=True)
return parser.parse_args()
def main():
"""
The main sequence of calls
:return:
"""
try:
args = parse_arguments()
except Exception:
print("Error parsing command line")
traceback.print_exc()
return
with open(args.pptx, "rb") as fh:
archive = ZipFile(BytesIO(fh.read()))
presentation = archive.read('ppt/presentation.xml')
dom = ET.fromstring(presentation)
xslt = ET.fromstring(xslt_src)
transform = ET.XSLT(xslt)
print(transform(dom))
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment