Created
September 13, 2024 13:18
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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> </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