
Pptx
- 977 installs
- 32k repo stars
- Updated July 29, 2026
- k-dense-ai/scientific-agent-skills
pptx is an agent skill that converts structured content into professional PowerPoint presentations using an existing deck as a reusable template with varied slide layouts.
About
pptx is a k-dense-ai scientific-agent-skills agent skill for template-based PowerPoint generation that avoids monotonous title-plus-bullet decks. The workflow starts by analyzing an existing template.pptx with python scripts/thumbnail.py to produce thumbnails.jpg and python -m markitdown to extract placeholder text, then maps each content section to a distinct template slide layout. The skill actively recommends multi-column, image-plus-text, full-bleed, and quote callout layouts instead of defaulting to basic bullets. Developers reach for pptx when an agent must produce presentation files from structured research or report content while preserving branded template styling.
- Analyzes existing PPTX templates via thumbnails and markitdown extraction
- Enforces layout variety: multi-column, image+text, full-bleed, quote, stat callouts, icon grids
- Unpacks PPTX into editable XML files for parallel subagent editing
- Requires completing all structural changes (delete, duplicate, reorder) before content edits
- Supports subagent parallel editing of individual slide{N}.xml files
Pptx by the numbers
- 977 all-time installs (skills.sh)
- +42 installs in the week ending Jul 29, 2026 (Skillselion tracking)
- Ranked #259 of 1,881 Documentation skills by installs in the Skillselion catalog
- Security screen: MEDIUM risk (skills.sh audit)
- Data as of Jul 29, 2026 (Skillselion catalog sync)
npx skills add https://github.com/k-dense-ai/scientific-agent-skills --skill pptxAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 977 |
|---|---|
| repo stars | ★ 32k |
| Security audit | 2 / 3 scanners passed |
| Last updated | July 29, 2026 |
| Repository | k-dense-ai/scientific-agent-skills ↗ |
How do you generate PowerPoint slides from a template deck?
Convert structured content into professional, varied-layout PowerPoint presentations using an existing deck as a reusable template.
Who is it for?
Developers or researchers who need agent-generated PowerPoint decks from structured content using an existing branded template.
Skip if: Developers needing live presentation delivery, Google Slides APIs, or slide decks built entirely from scratch without a template.
When should I use this skill?
The user wants to convert structured content into a PowerPoint presentation using an existing .pptx template with varied layouts.
What you get
PowerPoint .pptx files with mapped template layouts, thumbnails preview, and varied multi-column or image slide designs.
- populated .pptx deck
- thumbnails.jpg layout preview
Files
Editing Presentations
Template-Based Workflow
When using an existing presentation as a template:
1. Analyze existing slides:
python scripts/thumbnail.py template.pptx
python -m markitdown template.pptxReview thumbnails.jpg to see layouts, and markitdown output to see placeholder text.
2. Plan slide mapping: For each content section, choose a template slide.
⚠️ USE VARIED LAYOUTS — monotonous presentations are a common failure mode. Don't default to basic title + bullet slides. Actively seek out:
- Multi-column layouts (2-column, 3-column)
- Image + text combinations
- Full-bleed images with text overlay
- Quote or callout slides
- Section dividers
- Stat/number callouts
- Icon grids or icon + text rows
Avoid: Repeating the same text-heavy layout for every slide.
Match content type to layout style (e.g., key points → bullet slide, team info → multi-column, testimonials → quote slide).
3. Unpack: python scripts/office/unpack.py template.pptx unpacked/
4. Build presentation (do this yourself, not with subagents):
- Delete unwanted slides (remove from
<p:sldIdLst>) - Duplicate slides you want to reuse (
add_slide.py) - Reorder slides in
<p:sldIdLst> - Complete all structural changes before step 5
5. Edit content: Update text in each slide{N}.xml. Use subagents here if available — slides are separate XML files, so subagents can edit in parallel.
6. Clean: python scripts/clean.py unpacked/
7. Pack: python scripts/office/pack.py unpacked/ output.pptx --original template.pptx
---
Scripts
| Script | Purpose |
|---|---|
unpack.py | Extract and pretty-print PPTX |
add_slide.py | Duplicate slide or create from layout |
clean.py | Remove orphaned files |
pack.py | Repack with validation |
thumbnail.py | Create visual grid of slides |
unpack.py
python scripts/office/unpack.py input.pptx unpacked/Extracts PPTX, pretty-prints XML, escapes smart quotes.
add_slide.py
python scripts/add_slide.py unpacked/ slide2.xml # Duplicate slide
python scripts/add_slide.py unpacked/ slideLayout2.xml # From layoutPrints <p:sldId> to add to <p:sldIdLst> at desired position.
clean.py
python scripts/clean.py unpacked/Removes slides not in <p:sldIdLst>, unreferenced media, orphaned rels.
pack.py
python scripts/office/pack.py unpacked/ output.pptx --original input.pptxValidates, repairs, condenses XML, re-encodes smart quotes.
thumbnail.py
python scripts/thumbnail.py input.pptx [output_prefix] [--cols N]Creates thumbnails.jpg with slide filenames as labels. Default 3 columns, max 12 per grid.
Use for template analysis only (choosing layouts). For visual QA, use soffice + pdftoppm to create full-resolution individual slide images—see SKILL.md.
---
Slide Operations
Slide order is in ppt/presentation.xml → <p:sldIdLst>.
Reorder: Rearrange <p:sldId> elements.
Delete: Remove <p:sldId>, then run clean.py.
Add: Use add_slide.py. Never manually copy slide files—the script handles notes references, Content_Types.xml, and relationship IDs that manual copying misses.
---
Editing Content
Subagents: If available, use them here (after completing step 4). Each slide is a separate XML file, so subagents can edit in parallel. In your prompt to subagents, include:
- The slide file path(s) to edit
- "Use the Edit tool for all changes"
- The formatting rules and common pitfalls below
For each slide: 1. Read the slide's XML 2. Identify ALL placeholder content—text, images, charts, icons, captions 3. Replace each placeholder with final content
Use the Edit tool, not sed or Python scripts. The Edit tool forces specificity about what to replace and where, yielding better reliability.
Formatting Rules
- **Bold all headers, subh
Editing Presentations
Template-Based Workflow
When using an existing presentation as a template:
1. Analyze existing slides:
python scripts/thumbnail.py template.pptx
python -m markitdown template.pptxReview thumbnails.jpg to see layouts, and markitdown output to see placeholder text.
2. Plan slide mapping: For each content section, choose a template slide.
⚠️ USE VARIED LAYOUTS — monotonous presentations are a common failure mode. Don't default to basic title + bullet slides. Actively seek out:
- Multi-column layouts (2-column, 3-column)
- Image + text combinations
- Full-bleed images with text overlay
- Quote or callout slides
- Section dividers
- Stat/number callouts
- Icon grids or icon + text rows
Avoid: Repeating the same text-heavy layout for every slide.
Match content type to layout style (e.g., key points → bullet slide, team info → multi-column, testimonials → quote slide).
3. Unpack: python scripts/office/unpack.py template.pptx unpacked/
4. Build presentation (do this yourself, not with subagents):
- Delete unwanted slides (remove from
<p:sldIdLst>) - Duplicate slides you want to reuse (
add_slide.py) - Reorder slides in
<p:sldIdLst> - Complete all structural changes before step 5
5. Edit content: Update text in each slide{N}.xml. Use subagents here if available — slides are separate XML files, so subagents can edit in parallel.
6. Clean: python scripts/clean.py unpacked/
7. Pack: python scripts/office/pack.py unpacked/ output.pptx --original template.pptx
---
Scripts
| Script | Purpose |
|---|---|
unpack.py | Extract and pretty-print PPTX |
add_slide.py | Duplicate slide or create from layout |
clean.py | Remove orphaned files |
pack.py | Repack with validation |
thumbnail.py | Create visual grid of slides |
unpack.py
python scripts/office/unpack.py input.pptx unpacked/Extracts PPTX, pretty-prints XML, escapes smart quotes.
add_slide.py
python scripts/add_slide.py unpacked/ slide2.xml # Duplicate slide
python scripts/add_slide.py unpacked/ slideLayout2.xml # From layoutPrints <p:sldId> to add to <p:sldIdLst> at desired position.
clean.py
python scripts/clean.py unpacked/Removes slides not in <p:sldIdLst>, unreferenced media, orphaned rels.
pack.py
python scripts/office/pack.py unpacked/ output.pptx --original input.pptxValidates, repairs, condenses XML, re-encodes smart quotes.
thumbnail.py
python scripts/thumbnail.py input.pptx [output_prefix] [--cols N]Creates thumbnails.jpg with slide filenames as labels. Default 3 columns, max 12 per grid.
Use for template analysis only (choosing layouts). For visual QA, use soffice + pdftoppm to create full-resolution individual slide images—see SKILL.md.
---
Slide Operations
Slide order is in ppt/presentation.xml → <p:sldIdLst>.
Reorder: Rearrange <p:sldId> elements.
Delete: Remove <p:sldId>, then run clean.py.
Add: Use add_slide.py. Never manually copy slide files—the script handles notes references, Content_Types.xml, and relationship IDs that manual copying misses.
---
Editing Content
Subagents: If available, use them here (after completing step 4). Each slide is a separate XML file, so subagents can edit in parallel. In your prompt to subagents, include:
- The slide file path(s) to edit
- "Use the Edit tool for all changes"
- The formatting rules and common pitfalls below
For each slide: 1. Read the slide's XML 2. Identify ALL placeholder content—text, images, charts, icons, captions 3. Replace each placeholder with final content
Use the Edit tool, not sed or Python scripts. The Edit tool forces specificity about what to replace and where, yielding better reliability.
Formatting Rules
- Bold all headers, subheadings, and inline labels: Use
b="1"on<a:rPr>. This includes: - Slide titles
- Section headers within a slide
- Inline labels like (e.g.: "Status:", "Description:") at the start of a line
- Never use unicode bullets (•): Use proper list formatting with
<a:buChar>or<a:buAutoNum> - Bullet consistency: Let bullets inherit from the layout. Only specify
<a:buChar>or<a:buNone>.
---
Common Pitfalls
Template Adaptation
When source content has fewer items than the template:
- Remove excess elements entirely (images, shapes, text boxes), don't just clear text
- Check for orphaned visuals after clearing text content
- Run visual QA to catch mismatched counts
When replacing text with different length content:
- Shorter replacements: Usually safe
- Longer replacements: May overflow or wrap unexpectedly
- Test with visual QA after text changes
- Consider truncating or splitting content to fit the template's design constraints
Template slots ≠ Source items: If template has 4 team members but source has 3 users, delete the 4th member's entire group (image + text boxes), not just the text.
Multi-Item Content
If source has multiple items (numbered lists, multiple sections), create separate <a:p> elements for each — never concatenate into one string.
❌ WRONG — all items in one paragraph:
<a:p>
<a:r><a:rPr .../><a:t>Step 1: Do the first thing. Step 2: Do the second thing.</a:t></a:r>
</a:p>✅ CORRECT — separate paragraphs with bold headers:
<a:p>
<a:pPr algn="l"><a:lnSpc><a:spcPts val="3919"/></a:lnSpc></a:pPr>
<a:r><a:rPr lang="en-US" sz="2799" b="1" .../><a:t>Step 1</a:t></a:r>
</a:p>
<a:p>
<a:pPr algn="l"><a:lnSpc><a:spcPts val="3919"/></a:lnSpc></a:pPr>
<a:r><a:rPr lang="en-US" sz="2799" .../><a:t>Do the first thing.</a:t></a:r>
</a:p>
<a:p>
<a:pPr algn="l"><a:lnSpc><a:spcPts val="3919"/></a:lnSpc></a:pPr>
<a:r><a:rPr lang="en-US" sz="2799" b="1" .../><a:t>Step 2</a:t></a:r>
</a:p>
<!-- continue pattern -->Copy <a:pPr> from the original paragraph to preserve line spacing. Use b="1" on headers.
Smart Quotes
Handled automatically by unpack/pack. But the Edit tool converts smart quotes to ASCII.
When adding new text with quotes, use XML entities:
<a:t>the “Agreement”</a:t>| Character | Name | Unicode | XML Entity |
|---|---|---|---|
“ | Left double quote | U+201C | “ |
” | Right double quote | U+201D | ” |
‘ | Left single quote | U+2018 | ‘ |
’ | Right single quote | U+2019 | ’ |
Other
- Whitespace: Use
xml:space="preserve"on<a:t>with leading/trailing spaces - XML parsing: Use
defusedxml.minidom, notxml.etree.ElementTree(corrupts namespaces)
© 2025 Anthropic, PBC. All rights reserved.
LICENSE: Use of these materials (including all code, prompts, assets, files,
and other components of this Skill) is governed by your agreement with
Anthropic regarding use of Anthropic's services. If no separate agreement
exists, use is governed by Anthropic's Consumer Terms of Service or
Commercial Terms of Service, as applicable:
https://www.anthropic.com/legal/consumer-terms
https://www.anthropic.com/legal/commercial-terms
Your applicable agreement is referred to as the "Agreement." "Services" are
as defined in the Agreement.
ADDITIONAL RESTRICTIONS: Notwithstanding anything in the Agreement to the
contrary, users may not:
- Extract these materials from the Services or retain copies of these
materials outside the Services
- Reproduce or copy these materials, except for temporary copies created
automatically during authorized use of the Services
- Create derivative works based on these materials
- Distribute, sublicense, or transfer these materials to any third party
- Make, offer to sell, sell, or import any inventions embodied in these
materials
- Reverse engineer, decompile, or disassemble these materials
The receipt, viewing, or possession of these materials does not convey or
imply any license or right beyond those expressly granted above.
Anthropic retains all right, title, and interest in these materials,
including all copyrights, patents, and other intellectual property rights.
PptxGenJS Tutorial
Setup & Basic Structure
const pptxgen = require("pptxgenjs");
let pres = new pptxgen();
pres.layout = 'LAYOUT_16x9'; // or 'LAYOUT_16x10', 'LAYOUT_4x3', 'LAYOUT_WIDE'
pres.author = 'Your Name';
pres.title = 'Presentation Title';
let slide = pres.addSlide();
slide.addText("Hello World!", { x: 0.5, y: 0.5, fontSize: 36, color: "363636" });
pres.writeFile({ fileName: "Presentation.pptx" });Layout Dimensions
Slide dimensions (coordinates in inches):
LAYOUT_16x9: 10" × 5.625" (default)LAYOUT_16x10: 10" × 6.25"LAYOUT_4x3: 10" × 7.5"LAYOUT_WIDE: 13.3" × 7.5"
---
Text & Formatting
// Basic text
slide.addText("Simple Text", {
x: 1, y: 1, w: 8, h: 2, fontSize: 24, fontFace: "Arial",
color: "363636", bold: true, align: "center", valign: "middle"
});
// Character spacing (use charSpacing, not letterSpacing which is silently ignored)
slide.addText("SPACED TEXT", { x: 1, y: 1, w: 8, h: 1, charSpacing: 6 });
// Rich text arrays
slide.addText([
{ text: "Bold ", options: { bold: true } },
{ text: "Italic ", options: { italic: true } }
], { x: 1, y: 3, w: 8, h: 1 });
// Multi-line text (requires breakLine: true)
slide.addText([
{ text: "Line 1", options: { breakLine: true } },
{ text: "Line 2", options: { breakLine: true } },
{ text: "Line 3" } // Last item doesn't need breakLine
], { x: 0.5, y: 0.5, w: 8, h: 2 });
// Text box margin (internal padding)
slide.addText("Title", {
x: 0.5, y: 0.3, w: 9, h: 0.6,
margin: 0 // Use 0 when aligning text with other elements like shapes or icons
});Tip: Text boxes have internal margin by default. Set margin: 0 when you need text to align precisely with shapes, lines, or icons at the same x-position.
---
Lists & Bullets
// ✅ CORRECT: Multiple bullets
slide.addText([
{ text: "First item", options: { bullet: true, breakLine: true } },
{ text: "Second item", options: { bullet: true, breakLine: true } },
{ text: "Third item", options: { bullet: true } }
], { x: 0.5, y: 0.5, w: 8, h: 3 });
// ❌ WRONG: Never use unicode bullets
slide.addText("• First item", { ... }); // Creates double bullets
// Sub-items and numbered lists
{ text: "Sub-item", options: { bullet: true, indentLevel: 1 } }
{ text: "First", options: { bullet: { type: "number" }, breakLine: true } }---
Shapes
slide.addShape(pres.shapes.RECTANGLE, {
x: 0.5, y: 0.8, w: 1.5, h: 3.0,
fill: { color: "FF0000" }, line: { color: "000000", width: 2 }
});
slide.addShape(pres.shapes.OVAL, { x: 4, y: 1, w: 2, h: 2, fill: { color: "0000FF" } });
slide.addShape(pres.shapes.LINE, {
x: 1, y: 3, w: 5, h: 0, line: { color: "FF0000", width: 3, dashType: "dash" }
});
// With transparency
slide.addShape(pres.shapes.RECTANGLE, {
x: 1, y: 1, w: 3, h: 2,
fill: { color: "0088CC", transparency: 50 }
});
// Rounded rectangle (rectRadius only works with ROUNDED_RECTANGLE, not RECTANGLE)
// ⚠️ Don't pair with rectangular accent overlays — they won't cover rounded corners. Use RECTANGLE instead.
slide.addShape(pres.shapes.ROUNDED_RECTANGLE, {
x: 1, y: 1, w: 3, h: 2,
fill: { color: "FFFFFF" }, rectRadius: 0.1
});
// With shadow
slide.addShape(pres.shapes.RECTANGLE, {
x: 1, y: 1, w: 3, h: 2,
fill: { color: "FFFFFF" },
shadow: { type: "outer", color: "000000", blur: 6, offset: 2, angle: 135, opacity: 0.15 }
});Shadow options:
| Property | Type | Range | Notes |
|---|---|---|---|
type | string | "outer", "inner" | |
color | string | 6-char hex (e.g. "000000") | No # prefix, no 8-char hex — see Common Pitfalls |
blur | number | 0-100 pt | |
offset | number | 0-200 pt | Must be non-negative — negative values corrupt the file |
angle | number | 0-359 degrees | Direction the shadow falls (135 = bottom-right, 270 = upward) |
opacity | number | 0.0-1.0 | Use this for transparency, never encode in color string |
To cast a shadow upward (e.g. on a footer bar), use angle: 270 with a positive offset — do not use a negative offset.
Note: Gradient fills are not natively supported. Use a gradient image as a background instead.
---
Images
Image Sources
// From file path
slide.addImage({ path: "images/chart.png", x: 1, y: 1, w: 5, h: 3 });
// From URL
slide.addImage({ path: "https://example.com/image.jpg", x: 1, y: 1, w: 5, h: 3 });
// From base64 (faster, no file I/O)
slide.addImage({ data: "image/png;base64,iVBORw0KGgo...", x: 1, y: 1, w: 5, h: 3 });Image Options
slide.addImage({
path: "image.png",
x: 1, y: 1, w: 5, h: 3,
rotate: 45, // 0-359 degrees
rounding: true, // Circular crop
transparency: 50, // 0-100
flipH: true, // Horizontal flip
flipV: false, // Vertical flip
altText: "Description", // Accessibility
hyperlink: { url: "https://example.com" }
});Image Sizing Modes
// Contain - fit inside, preserve ratio
{ sizing: { type: 'contain', w: 4, h: 3 } }
// Cover - fill area, preserve ratio (may crop)
{ sizing: { type: 'cover', w: 4, h: 3 } }
// Crop - cut specific portion
{ sizing: { type: 'crop', x: 0.5, y: 0.5, w: 2, h: 2 } }Calculate Dimensions (preserve aspect ratio)
const origWidth = 1978, origHeight = 923, maxHeight = 3.0;
const calcWidth = maxHeight * (origWidth / origHeight);
const centerX = (10 - calcWidth) / 2;
slide.addImage({ path: "image.png", x: centerX, y: 1.2, w: calcWidth, h: maxHeight });Supported Formats
- Standard: PNG, JPG, GIF (animated GIFs work in Microsoft 365)
- SVG: Works in modern PowerPoint/Microsoft 365
---
Icons
Use react-icons to generate SVG icons, then rasterize to PNG for universal compatibility.
Setup
const React = require("react");
const ReactDOMServer = require("react-dom/server");
const sharp = require("sharp");
const { FaCheckCircle, FaChartLine } = require("react-icons/fa");
function renderIconSvg(IconComponent, color = "#000000", size = 256) {
return ReactDOMServer.renderToStaticMarkup(
React.createElement(IconComponent, { color, size: String(size) })
);
}
async function iconToBase64Png(IconComponent, color, size = 256) {
const svg = renderIconSvg(IconComponent, color, size);
const pngBuffer = await sharp(Buffer.from(svg)).png().toBuffer();
return "image/png;base64," + pngBuffer.toString("base64");
}Add Icon to Slide
const iconData = await iconToBase64Png(FaCheckCircle, "#4472C4", 256);
slide.addImage({
data: iconData,
x: 1, y: 1, w: 0.5, h: 0.5 // Size in inches
});Note: Use size 256 or higher for crisp icons. The size parameter controls the rasterization resolution, not the display size on the slide (which is set by w and h in inches).
Icon Libraries
Install: npm install -g react-icons react react-dom sharp
Popular icon sets in react-icons:
react-icons/fa- Font Awesomereact-icons/md- Material Designreact-icons/hi- Heroiconsreact-icons/bi- Bootstrap Icons
---
Slide Backgrounds
// Solid color
slide.background = { color: "F1F1F1" };
// Color with transparency
slide.background = { color: "FF3399", transparency: 50 };
// Image from URL
slide.background = { path: "https://example.com/bg.jpg" };
// Image from base64
slide.background = { data: "image/png;base64,iVBORw0KGgo..." };---
Tables
slide.addTable([
["Header 1", "Header 2"],
["Cell 1", "Cell 2"]
], {
x: 1, y: 1, w: 8, h: 2,
border: { pt: 1, color: "999999" }, fill: { color: "F1F1F1" }
});
// Advanced with merged cells
let tableData = [
[{ text: "Header", options: { fill: { color: "6699CC" }, color: "FFFFFF", bold: true } }, "Cell"],
[{ text: "Merged", options: { colspan: 2 } }]
];
slide.addTable(tableData, { x: 1, y: 3.5, w: 8, colW: [4, 4] });---
Charts
// Bar chart
slide.addChart(pres.charts.BAR, [{
name: "Sales", labels: ["Q1", "Q2", "Q3", "Q4"], values: [4500, 5500, 6200, 7100]
}], {
x: 0.5, y: 0.6, w: 6, h: 3, barDir: 'col',
showTitle: true, title: 'Quarterly Sales'
});
// Line chart
slide.addChart(pres.charts.LINE, [{
name: "Temp", labels: ["Jan", "Feb", "Mar"], values: [32, 35, 42]
}], { x: 0.5, y: 4, w: 6, h: 3, lineSize: 3, lineSmooth: true });
// Pie chart
slide.addChart(pres.charts.PIE, [{
name: "Share", labels: ["A", "B", "Other"], values: [35, 45, 20]
}], { x: 7, y: 1, w: 5, h: 4, showPercent: true });Better-Looking Charts
Default charts look dated. Apply these options for a modern, clean appearance:
slide.addChart(pres.charts.BAR, chartData, {
x: 0.5, y: 1, w: 9, h: 4, barDir: "col",
// Custom colors (match your presentation palette)
chartColors: ["0D9488", "14B8A6", "5EEAD4"],
// Clean background
chartArea: { fill: { color: "FFFFFF" }, roundedCorners: true },
// Muted axis labels
catAxisLabelColor: "64748B",
valAxisLabelColor: "64748B",
// Subtle grid (value axis only)
valGridLine: { color: "E2E8F0", size: 0.5 },
catGridLine: { style: "none" },
// Data labels on bars
showValue: true,
dataLabelPosition: "outEnd",
dataLabelColor: "1E293B",
// Hide legend for single series
showLegend: false,
});Key styling options:
chartColors: [...]- hex colors for series/segmentschartArea: { fill, border, roundedCorners }- chart backgroundcatGridLine/valGridLine: { color, style, size }- grid lines (style: "none"to hide)lineSmooth: true- curved lines (line charts)legendPos: "r"- legend position: "b", "t", "l", "r", "tr"
---
Slide Masters
pres.defineSlideMaster({
title: 'TITLE_SLIDE', background: { color: '283A5E' },
objects: [{
placeholder: { options: { name: 'title', type: 'title', x: 1, y: 2, w: 8, h: 2 } }
}]
});
let titleSlide = pres.addSlide({ masterName: "TITLE_SLIDE" });
titleSlide.addText("My Title", { placeholder: "title" });---
Common Pitfalls
⚠️ These issues cause file corruption, visual bugs, or broken output. Avoid them.
1. NEVER use "#" with hex colors - causes file corruption
color: "FF0000" // ✅ CORRECT
color: "#FF0000" // ❌ WRONG2. NEVER encode opacity in hex color strings - 8-char colors (e.g., "00000020") corrupt the file. Use the opacity property instead.
shadow: { type: "outer", blur: 6, offset: 2, color: "00000020" } // ❌ CORRUPTS FILE
shadow: { type: "outer", blur: 6, offset: 2, color: "000000", opacity: 0.12 } // ✅ CORRECT3. Use `bullet: true` - NEVER unicode symbols like "•" (creates double bullets)
4. Use `breakLine: true` between array items or text runs together
5. Avoid `lineSpacing` with bullets - causes excessive gaps; use paraSpaceAfter instead
6. Each presentation needs fresh instance - don't reuse pptxgen() objects
7. NEVER reuse option objects across calls - PptxGenJS mutates objects in-place (e.g. converting shadow values to EMU). Sharing one object between multiple calls corrupts the second shape.
const shadow = { type: "outer", blur: 6, offset: 2, color: "000000", opacity: 0.15 };
slide.addShape(pres.shapes.RECTANGLE, { shadow, ... }); // ❌ second call gets already-converted values
slide.addShape(pres.shapes.RECTANGLE, { shadow, ... });
const makeShadow = () => ({ type: "outer", blur: 6, offset: 2, color: "000000", opacity: 0.15 });
slide.addShape(pres.shapes.RECTANGLE, { shadow: makeShadow(), ... }); // ✅ fresh object each time
slide.addShape(pres.shapes.RECTANGLE, { shadow: makeShadow(), ... });8. Don't use `ROUNDED_RECTANGLE` with accent borders - rectangular overlay bars won't cover rounded corners. Use RECTANGLE instead.
// ❌ WRONG: Accent bar doesn't cover rounded corners
slide.addShape(pres.shapes.ROUNDED_RECTANGLE, { x: 1, y: 1, w: 3, h: 1.5, fill: { color: "FFFFFF" } });
slide.addShape(pres.shapes.RECTANGLE, { x: 1, y: 1, w: 0.08, h: 1.5, fill: { color: "0891B2" } });
// ✅ CORRECT: Use RECTANGLE for clean alignment
slide.addShape(pres.shapes.RECTANGLE, { x: 1, y: 1, w: 3, h: 1.5, fill: { color: "FFFFFF" } });
slide.addShape(pres.shapes.RECTANGLE, { x: 1, y: 1, w: 0.08, h: 1.5, fill: { color: "0891B2" } });---
Quick Reference
- Shapes: RECTANGLE, OVAL, LINE, ROUNDED_RECTANGLE
- Charts: BAR, LINE, PIE, DOUGHNUT, SCATTER, BUBBLE, RADAR
- Layouts: LAYOUT_16x9 (10"×5.625"), LAYOUT_16x10, LAYOUT_4x3, LAYOUT_WIDE
- Alignment: "left", "center", "right"
- Chart data labels: "outEnd", "inEnd", "center"
"""Add a new slide to an unpacked PPTX directory.
Usage: python add_slide.py <unpacked_dir> <source>
The source can be:
- A slide file (e.g., slide2.xml) - duplicates the slide
- A layout file (e.g., slideLayout2.xml) - creates from layout
Examples:
python add_slide.py unpacked/ slide2.xml
# Duplicates slide2, creates slide5.xml
python add_slide.py unpacked/ slideLayout2.xml
# Creates slide5.xml from slideLayout2.xml
To see available layouts: ls unpacked/ppt/slideLayouts/
Prints the <p:sldId> element to add to presentation.xml.
"""
import re
import shutil
import sys
from pathlib import Path
def get_next_slide_number(slides_dir: Path) -> int:
existing = [int(m.group(1)) for f in slides_dir.glob("slide*.xml")
if (m := re.match(r"slide(\d+)\.xml", f.name))]
return max(existing) + 1 if existing else 1
def create_slide_from_layout(unpacked_dir: Path, layout_file: str) -> None:
slides_dir = unpacked_dir / "ppt" / "slides"
rels_dir = slides_dir / "_rels"
layouts_dir = unpacked_dir / "ppt" / "slideLayouts"
layout_path = layouts_dir / layout_file
if not layout_path.exists():
print(f"Error: {layout_path} not found", file=sys.stderr)
sys.exit(1)
next_num = get_next_slide_number(slides_dir)
dest = f"slide{next_num}.xml"
dest_slide = slides_dir / dest
dest_rels = rels_dir / f"{dest}.rels"
slide_xml = '''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<p:sld xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main">
<p:cSld>
<p:spTree>
<p:nvGrpSpPr>
<p:cNvPr id="1" name=""/>
<p:cNvGrpSpPr/>
<p:nvPr/>
</p:nvGrpSpPr>
<p:grpSpPr>
<a:xfrm>
<a:off x="0" y="0"/>
<a:ext cx="0" cy="0"/>
<a:chOff x="0" y="0"/>
<a:chExt cx="0" cy="0"/>
</a:xfrm>
</p:grpSpPr>
</p:spTree>
</p:cSld>
<p:clrMapOvr>
<a:masterClrMapping/>
</p:clrMapOvr>
</p:sld>'''
dest_slide.write_text(slide_xml, encoding="utf-8")
rels_dir.mkdir(exist_ok=True)
rels_xml = f'''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout" Target="../slideLayouts/{layout_file}"/>
</Relationships>'''
dest_rels.write_text(rels_xml, encoding="utf-8")
_add_to_content_types(unpacked_dir, dest)
rid = _add_to_presentation_rels(unpacked_dir, dest)
next_slide_id = _get_next_slide_id(unpacked_dir)
print(f"Created {dest} from {layout_file}")
print(f'Add to presentation.xml <p:sldIdLst>: <p:sldId id="{next_slide_id}" r:id="{rid}"/>')
def duplicate_slide(unpacked_dir: Path, source: str) -> None:
slides_dir = unpacked_dir / "ppt" / "slides"
rels_dir = slides_dir / "_rels"
source_slide = slides_dir / source
if not source_slide.exists():
print(f"Error: {source_slide} not found", file=sys.stderr)
sys.exit(1)
next_num = get_next_slide_number(slides_dir)
dest = f"slide{next_num}.xml"
dest_slide = slides_dir / dest
source_rels = rels_dir / f"{source}.rels"
dest_rels = rels_dir / f"{dest}.rels"
shutil.copy2(source_slide, dest_slide)
if source_rels.exists():
shutil.copy2(source_rels, dest_rels)
rels_content = dest_rels.read_text(encoding="utf-8")
rels_content = re.sub(
r'\s*<Relationship[^>]*Type="[^"]*notesSlide"[^>]*/>\s*',
"\n",
rels_content,
)
dest_rels.write_text(rels_content, encoding="utf-8")
_add_to_content_types(unpacked_dir, dest)
rid = _add_to_presentation_rels(unpacked_dir, dest)
next_slide_id = _get_next_slide_id(unpacked_dir)
print(f"Created {dest} from {source}")
print(f'Add to presentation.xml <p:sldIdLst>: <p:sldId id="{next_slide_id}" r:id="{rid}"/>')
def _add_to_content_types(unpacked_dir: Path, dest: str) -> None:
content_types_path = unpacked_dir / "[Content_Types].xml"
content_types = content_types_path.read_text(encoding="utf-8")
new_override = f'<Override PartName="/ppt/slides/{dest}" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slide+xml"/>'
if f"/ppt/slides/{dest}" not in content_types:
content_types = content_types.replace("</Types>", f" {new_override}\n</Types>")
content_types_path.write_text(content_types, encoding="utf-8")
def _add_to_presentation_rels(unpacked_dir: Path, dest: str) -> str:
pres_rels_path = unpacked_dir / "ppt" / "_rels" / "presentation.xml.rels"
pres_rels = pres_rels_path.read_text(encoding="utf-8")
rids = [int(m) for m in re.findall(r'Id="rId(\d+)"', pres_rels)]
next_rid = max(rids) + 1 if rids else 1
rid = f"rId{next_rid}"
new_rel = f'<Relationship Id="{rid}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide" Target="slides/{dest}"/>'
if f"slides/{dest}" not in pres_rels:
pres_rels = pres_rels.replace("</Relationships>", f" {new_rel}\n</Relationships>")
pres_rels_path.write_text(pres_rels, encoding="utf-8")
return rid
def _get_next_slide_id(unpacked_dir: Path) -> int:
pres_path = unpacked_dir / "ppt" / "presentation.xml"
pres_content = pres_path.read_text(encoding="utf-8")
slide_ids = [int(m) for m in re.findall(r'<p:sldId[^>]*id="(\d+)"', pres_content)]
return max(slide_ids) + 1 if slide_ids else 256
def parse_source(source: str) -> tuple[str, str | None]:
if source.startswith("slideLayout") and source.endswith(".xml"):
return ("layout", source)
return ("slide", None)
if __name__ == "__main__":
if len(sys.argv) != 3:
print("Usage: python add_slide.py <unpacked_dir> <source>", file=sys.stderr)
print("", file=sys.stderr)
print("Source can be:", file=sys.stderr)
print(" slide2.xml - duplicate an existing slide", file=sys.stderr)
print(" slideLayout2.xml - create from a layout template", file=sys.stderr)
print("", file=sys.stderr)
print("To see available layouts: ls <unpacked_dir>/ppt/slideLayouts/", file=sys.stderr)
sys.exit(1)
unpacked_dir = Path(sys.argv[1])
source = sys.argv[2]
if not unpacked_dir.exists():
print(f"Error: {unpacked_dir} not found", file=sys.stderr)
sys.exit(1)
source_type, layout_file = parse_source(source)
if source_type == "layout" and layout_file is not None:
create_slide_from_layout(unpacked_dir, layout_file)
else:
duplicate_slide(unpacked_dir, source)
"""Remove unreferenced files from an unpacked PPTX directory.
Usage: python clean.py <unpacked_dir>
Example:
python clean.py unpacked/
This script removes:
- Orphaned slides (not in sldIdLst) and their relationships
- [trash] directory (unreferenced files)
- Orphaned .rels files for deleted resources
- Unreferenced media, embeddings, charts, diagrams, drawings, ink files
- Unreferenced theme files
- Unreferenced notes slides
- Content-Type overrides for deleted files
"""
import sys
from pathlib import Path
import defusedxml.minidom
import re
def get_slides_in_sldidlst(unpacked_dir: Path) -> set[str]:
pres_path = unpacked_dir / "ppt" / "presentation.xml"
pres_rels_path = unpacked_dir / "ppt" / "_rels" / "presentation.xml.rels"
if not pres_path.exists() or not pres_rels_path.exists():
return set()
rels_dom = defusedxml.minidom.parse(str(pres_rels_path))
rid_to_slide = {}
for rel in rels_dom.getElementsByTagName("Relationship"):
rid = rel.getAttribute("Id")
target = rel.getAttribute("Target")
rel_type = rel.getAttribute("Type")
if "slide" in rel_type and target.startswith("slides/"):
rid_to_slide[rid] = target.replace("slides/", "")
pres_content = pres_path.read_text(encoding="utf-8")
referenced_rids = set(re.findall(r'<p:sldId[^>]*r:id="([^"]+)"', pres_content))
return {rid_to_slide[rid] for rid in referenced_rids if rid in rid_to_slide}
def remove_orphaned_slides(unpacked_dir: Path) -> list[str]:
slides_dir = unpacked_dir / "ppt" / "slides"
slides_rels_dir = slides_dir / "_rels"
pres_rels_path = unpacked_dir / "ppt" / "_rels" / "presentation.xml.rels"
if not slides_dir.exists():
return []
referenced_slides = get_slides_in_sldidlst(unpacked_dir)
removed = []
for slide_file in slides_dir.glob("slide*.xml"):
if slide_file.name not in referenced_slides:
rel_path = slide_file.relative_to(unpacked_dir)
slide_file.unlink()
removed.append(str(rel_path))
rels_file = slides_rels_dir / f"{slide_file.name}.rels"
if rels_file.exists():
rels_file.unlink()
removed.append(str(rels_file.relative_to(unpacked_dir)))
if removed and pres_rels_path.exists():
rels_dom = defusedxml.minidom.parse(str(pres_rels_path))
changed = False
for rel in list(rels_dom.getElementsByTagName("Relationship")):
target = rel.getAttribute("Target")
if target.startswith("slides/"):
slide_name = target.replace("slides/", "")
if slide_name not in referenced_slides:
if rel.parentNode:
rel.parentNode.removeChild(rel)
changed = True
if changed:
with open(pres_rels_path, "wb") as f:
f.write(rels_dom.toxml(encoding="utf-8"))
return removed
def remove_trash_directory(unpacked_dir: Path) -> list[str]:
trash_dir = unpacked_dir / "[trash]"
removed = []
if trash_dir.exists() and trash_dir.is_dir():
for file_path in trash_dir.iterdir():
if file_path.is_file():
rel_path = file_path.relative_to(unpacked_dir)
removed.append(str(rel_path))
file_path.unlink()
trash_dir.rmdir()
return removed
def get_slide_referenced_files(unpacked_dir: Path) -> set:
referenced = set()
slides_rels_dir = unpacked_dir / "ppt" / "slides" / "_rels"
if not slides_rels_dir.exists():
return referenced
for rels_file in slides_rels_dir.glob("*.rels"):
dom = defusedxml.minidom.parse(str(rels_file))
for rel in dom.getElementsByTagName("Relationship"):
target = rel.getAttribute("Target")
if not target:
continue
target_path = (rels_file.parent.parent / target).resolve()
try:
referenced.add(target_path.relative_to(unpacked_dir.resolve()))
except ValueError:
pass
return referenced
def remove_orphaned_rels_files(unpacked_dir: Path) -> list[str]:
resource_dirs = ["charts", "diagrams", "drawings"]
removed = []
slide_referenced = get_slide_referenced_files(unpacked_dir)
for dir_name in resource_dirs:
rels_dir = unpacked_dir / "ppt" / dir_name / "_rels"
if not rels_dir.exists():
continue
for rels_file in rels_dir.glob("*.rels"):
resource_file = rels_dir.parent / rels_file.name.replace(".rels", "")
try:
resource_rel_path = resource_file.resolve().relative_to(unpacked_dir.resolve())
except ValueError:
continue
if not resource_file.exists() or resource_rel_path not in slide_referenced:
rels_file.unlink()
rel_path = rels_file.relative_to(unpacked_dir)
removed.append(str(rel_path))
return removed
def get_referenced_files(unpacked_dir: Path) -> set:
referenced = set()
for rels_file in unpacked_dir.rglob("*.rels"):
dom = defusedxml.minidom.parse(str(rels_file))
for rel in dom.getElementsByTagName("Relationship"):
target = rel.getAttribute("Target")
if not target:
continue
target_path = (rels_file.parent.parent / target).resolve()
try:
referenced.add(target_path.relative_to(unpacked_dir.resolve()))
except ValueError:
pass
return referenced
def remove_orphaned_files(unpacked_dir: Path, referenced: set) -> list[str]:
resource_dirs = ["media", "embeddings", "charts", "diagrams", "tags", "drawings", "ink"]
removed = []
for dir_name in resource_dirs:
dir_path = unpacked_dir / "ppt" / dir_name
if not dir_path.exists():
continue
for file_path in dir_path.glob("*"):
if not file_path.is_file():
continue
rel_path = file_path.relative_to(unpacked_dir)
if rel_path not in referenced:
file_path.unlink()
removed.append(str(rel_path))
theme_dir = unpacked_dir / "ppt" / "theme"
if theme_dir.exists():
for file_path in theme_dir.glob("theme*.xml"):
rel_path = file_path.relative_to(unpacked_dir)
if rel_path not in referenced:
file_path.unlink()
removed.append(str(rel_path))
theme_rels = theme_dir / "_rels" / f"{file_path.name}.rels"
if theme_rels.exists():
theme_rels.unlink()
removed.append(str(theme_rels.relative_to(unpacked_dir)))
notes_dir = unpacked_dir / "ppt" / "notesSlides"
if notes_dir.exists():
for file_path in notes_dir.glob("*.xml"):
if not file_path.is_file():
continue
rel_path = file_path.relative_to(unpacked_dir)
if rel_path not in referenced:
file_path.unlink()
removed.append(str(rel_path))
notes_rels_dir = notes_dir / "_rels"
if notes_rels_dir.exists():
for file_path in notes_rels_dir.glob("*.rels"):
notes_file = notes_dir / file_path.name.replace(".rels", "")
if not notes_file.exists():
file_path.unlink()
removed.append(str(file_path.relative_to(unpacked_dir)))
return removed
def update_content_types(unpacked_dir: Path, removed_files: list[str]) -> None:
ct_path = unpacked_dir / "[Content_Types].xml"
if not ct_path.exists():
return
dom = defusedxml.minidom.parse(str(ct_path))
changed = False
for override in list(dom.getElementsByTagName("Override")):
part_name = override.getAttribute("PartName").lstrip("/")
if part_name in removed_files:
if override.parentNode:
override.parentNode.removeChild(override)
changed = True
if changed:
with open(ct_path, "wb") as f:
f.write(dom.toxml(encoding="utf-8"))
def clean_unused_files(unpacked_dir: Path) -> list[str]:
all_removed = []
slides_removed = remove_orphaned_slides(unpacked_dir)
all_removed.extend(slides_removed)
trash_removed = remove_trash_directory(unpacked_dir)
all_removed.extend(trash_removed)
while True:
removed_rels = remove_orphaned_rels_files(unpacked_dir)
referenced = get_referenced_files(unpacked_dir)
removed_files = remove_orphaned_files(unpacked_dir, referenced)
total_removed = removed_rels + removed_files
if not total_removed:
break
all_removed.extend(total_removed)
if all_removed:
update_content_types(unpacked_dir, all_removed)
return all_removed
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python clean.py <unpacked_dir>", file=sys.stderr)
print("Example: python clean.py unpacked/", file=sys.stderr)
sys.exit(1)
unpacked_dir = Path(sys.argv[1])
if not unpacked_dir.exists():
print(f"Error: {unpacked_dir} not found", file=sys.stderr)
sys.exit(1)
removed = clean_unused_files(unpacked_dir)
if removed:
print(f"Removed {len(removed)} unreferenced files:")
for f in removed:
print(f" {f}")
else:
print("No unreferenced files found")
"""Merge adjacent runs with identical formatting in DOCX.
Merges adjacent <w:r> elements that have identical <w:rPr> properties.
Works on runs in paragraphs and inside tracked changes (<w:ins>, <w:del>).
Also:
- Removes rsid attributes from runs (revision metadata that doesn't affect rendering)
- Removes proofErr elements (spell/grammar markers that block merging)
"""
from pathlib import Path
import defusedxml.minidom
def merge_runs(input_dir: str) -> tuple[int, str]:
doc_xml = Path(input_dir) / "word" / "document.xml"
if not doc_xml.exists():
return 0, f"Error: {doc_xml} not found"
try:
dom = defusedxml.minidom.parseString(doc_xml.read_text(encoding="utf-8"))
root = dom.documentElement
_remove_elements(root, "proofErr")
_strip_run_rsid_attrs(root)
containers = {run.parentNode for run in _find_elements(root, "r")}
merge_count = 0
for container in containers:
merge_count += _merge_runs_in(container)
doc_xml.write_bytes(dom.toxml(encoding="UTF-8"))
return merge_count, f"Merged {merge_count} runs"
except Exception as e:
return 0, f"Error: {e}"
def _find_elements(root, tag: str) -> list:
results = []
def traverse(node):
if node.nodeType == node.ELEMENT_NODE:
name = node.localName or node.tagName
if name == tag or name.endswith(f":{tag}"):
results.append(node)
for child in node.childNodes:
traverse(child)
traverse(root)
return results
def _get_child(parent, tag: str):
for child in parent.childNodes:
if child.nodeType == child.ELEMENT_NODE:
name = child.localName or child.tagName
if name == tag or name.endswith(f":{tag}"):
return child
return None
def _get_children(parent, tag: str) -> list:
results = []
for child in parent.childNodes:
if child.nodeType == child.ELEMENT_NODE:
name = child.localName or child.tagName
if name == tag or name.endswith(f":{tag}"):
results.append(child)
return results
def _is_adjacent(elem1, elem2) -> bool:
node = elem1.nextSibling
while node:
if node == elem2:
return True
if node.nodeType == node.ELEMENT_NODE:
return False
if node.nodeType == node.TEXT_NODE and node.data.strip():
return False
node = node.nextSibling
return False
def _remove_elements(root, tag: str):
for elem in _find_elements(root, tag):
if elem.parentNode:
elem.parentNode.removeChild(elem)
def _strip_run_rsid_attrs(root):
for run in _find_elements(root, "r"):
for attr in list(run.attributes.values()):
if "rsid" in attr.name.lower():
run.removeAttribute(attr.name)
def _merge_runs_in(container) -> int:
merge_count = 0
run = _first_child_run(container)
while run:
while True:
next_elem = _next_element_sibling(run)
if next_elem and _is_run(next_elem) and _can_merge(run, next_elem):
_merge_run_content(run, next_elem)
container.removeChild(next_elem)
merge_count += 1
else:
break
_consolidate_text(run)
run = _next_sibling_run(run)
return merge_count
def _first_child_run(container):
for child in container.childNodes:
if child.nodeType == child.ELEMENT_NODE and _is_run(child):
return child
return None
def _next_element_sibling(node):
sibling = node.nextSibling
while sibling:
if sibling.nodeType == sibling.ELEMENT_NODE:
return sibling
sibling = sibling.nextSibling
return None
def _next_sibling_run(node):
sibling = node.nextSibling
while sibling:
if sibling.nodeType == sibling.ELEMENT_NODE:
if _is_run(sibling):
return sibling
sibling = sibling.nextSibling
return None
def _is_run(node) -> bool:
name = node.localName or node.tagName
return name == "r" or name.endswith(":r")
def _can_merge(run1, run2) -> bool:
rpr1 = _get_child(run1, "rPr")
rpr2 = _get_child(run2, "rPr")
if (rpr1 is None) != (rpr2 is None):
return False
if rpr1 is None:
return True
return rpr1.toxml() == rpr2.toxml()
def _merge_run_content(target, source):
for child in list(source.childNodes):
if child.nodeType == child.ELEMENT_NODE:
name = child.localName or child.tagName
if name != "rPr" and not name.endswith(":rPr"):
target.appendChild(child)
def _consolidate_text(run):
t_elements = _get_children(run, "t")
for i in range(len(t_elements) - 1, 0, -1):
curr, prev = t_elements[i], t_elements[i - 1]
if _is_adjacent(prev, curr):
prev_text = prev.firstChild.data if prev.firstChild else ""
curr_text = curr.firstChild.data if curr.firstChild else ""
merged = prev_text + curr_text
if prev.firstChild:
prev.firstChild.data = merged
else:
prev.appendChild(run.ownerDocument.createTextNode(merged))
if merged.startswith(" ") or merged.endswith(" "):
prev.setAttribute("xml:space", "preserve")
elif prev.hasAttribute("xml:space"):
prev.removeAttribute("xml:space")
run.removeChild(curr)
"""Simplify tracked changes by merging adjacent w:ins or w:del elements.
Merges adjacent <w:ins> elements from the same author into a single element.
Same for <w:del> elements. This makes heavily-redlined documents easier to
work with by reducing the number of tracked change wrappers.
Rules:
- Only merges w:ins with w:ins, w:del with w:del (same element type)
- Only merges if same author (ignores timestamp differences)
- Only merges if truly adjacent (only whitespace between them)
"""
import xml.etree.ElementTree as ET
import zipfile
from pathlib import Path
import defusedxml.minidom
WORD_NS = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
def simplify_redlines(input_dir: str) -> tuple[int, str]:
doc_xml = Path(input_dir) / "word" / "document.xml"
if not doc_xml.exists():
return 0, f"Error: {doc_xml} not found"
try:
dom = defusedxml.minidom.parseString(doc_xml.read_text(encoding="utf-8"))
root = dom.documentElement
merge_count = 0
containers = _find_elements(root, "p") + _find_elements(root, "tc")
for container in containers:
merge_count += _merge_tracked_changes_in(container, "ins")
merge_count += _merge_tracked_changes_in(container, "del")
doc_xml.write_bytes(dom.toxml(encoding="UTF-8"))
return merge_count, f"Simplified {merge_count} tracked changes"
except Exception as e:
return 0, f"Error: {e}"
def _merge_tracked_changes_in(container, tag: str) -> int:
merge_count = 0
tracked = [
child
for child in container.childNodes
if child.nodeType == child.ELEMENT_NODE and _is_element(child, tag)
]
if len(tracked) < 2:
return 0
i = 0
while i < len(tracked) - 1:
curr = tracked[i]
next_elem = tracked[i + 1]
if _can_merge_tracked(curr, next_elem):
_merge_tracked_content(curr, next_elem)
container.removeChild(next_elem)
tracked.pop(i + 1)
merge_count += 1
else:
i += 1
return merge_count
def _is_element(node, tag: str) -> bool:
name = node.localName or node.tagName
return name == tag or name.endswith(f":{tag}")
def _get_author(elem) -> str:
author = elem.getAttribute("w:author")
if not author:
for attr in elem.attributes.values():
if attr.localName == "author" or attr.name.endswith(":author"):
return attr.value
return author
def _can_merge_tracked(elem1, elem2) -> bool:
if _get_author(elem1) != _get_author(elem2):
return False
node = elem1.nextSibling
while node and node != elem2:
if node.nodeType == node.ELEMENT_NODE:
return False
if node.nodeType == node.TEXT_NODE and node.data.strip():
return False
node = node.nextSibling
return True
def _merge_tracked_content(target, source):
while source.firstChild:
child = source.firstChild
source.removeChild(child)
target.appendChild(child)
def _find_elements(root, tag: str) -> list:
results = []
def traverse(node):
if node.nodeType == node.ELEMENT_NODE:
name = node.localName or node.tagName
if name == tag or name.endswith(f":{tag}"):
results.append(node)
for child in node.childNodes:
traverse(child)
traverse(root)
return results
def get_tracked_change_authors(doc_xml_path: Path) -> dict[str, int]:
if not doc_xml_path.exists():
return {}
try:
tree = ET.parse(doc_xml_path)
root = tree.getroot()
except ET.ParseError:
return {}
namespaces = {"w": WORD_NS}
author_attr = f"{{{WORD_NS}}}author"
authors: dict[str, int] = {}
for tag in ["ins", "del"]:
for elem in root.findall(f".//w:{tag}", namespaces):
author = elem.get(author_attr)
if author:
authors[author] = authors.get(author, 0) + 1
return authors
def _get_authors_from_docx(docx_path: Path) -> dict[str, int]:
try:
with zipfile.ZipFile(docx_path, "r") as zf:
if "word/document.xml" not in zf.namelist():
return {}
with zf.open("word/document.xml") as f:
tree = ET.parse(f)
root = tree.getroot()
namespaces = {"w": WORD_NS}
author_attr = f"{{{WORD_NS}}}author"
authors: dict[str, int] = {}
for tag in ["ins", "del"]:
for elem in root.findall(f".//w:{tag}", namespaces):
author = elem.get(author_attr)
if author:
authors[author] = authors.get(author, 0) + 1
return authors
except (zipfile.BadZipFile, ET.ParseError):
return {}
def infer_author(modified_dir: Path, original_docx: Path, default: str = "Claude") -> str:
modified_xml = modified_dir / "word" / "document.xml"
modified_authors = get_tracked_change_authors(modified_xml)
if not modified_authors:
return default
original_authors = _get_authors_from_docx(original_docx)
new_changes: dict[str, int] = {}
for author, count in modified_authors.items():
original_count = original_authors.get(author, 0)
diff = count - original_count
if diff > 0:
new_changes[author] = diff
if not new_changes:
return default
if len(new_changes) == 1:
return next(iter(new_changes))
raise ValueError(
f"Multiple authors added new changes: {new_changes}. "
"Cannot infer which author to validate."
)
"""Pack a directory into a DOCX, PPTX, or XLSX file.
Validates with auto-repair, condenses XML formatting, and creates the Office file.
Usage:
python pack.py <input_directory> <output_file> [--original <file>] [--validate true|false]
Examples:
python pack.py unpacked/ output.docx --original input.docx
python pack.py unpacked/ output.pptx --validate false
"""
import argparse
import sys
import shutil
import tempfile
import zipfile
from pathlib import Path
import defusedxml.minidom
from validators import DOCXSchemaValidator, PPTXSchemaValidator, RedliningValidator
def pack(
input_directory: str,
output_file: str,
original_file: str | None = None,
validate: bool = True,
infer_author_func=None,
) -> tuple[None, str]:
input_dir = Path(input_directory)
output_path = Path(output_file)
suffix = output_path.suffix.lower()
if not input_dir.is_dir():
return None, f"Error: {input_dir} is not a directory"
if suffix not in {".docx", ".pptx", ".xlsx"}:
return None, f"Error: {output_file} must be a .docx, .pptx, or .xlsx file"
if validate and original_file:
original_path = Path(original_file)
if original_path.exists():
success, output = _run_validation(
input_dir, original_path, suffix, infer_author_func
)
if output:
print(output)
if not success:
return None, f"Error: Validation failed for {input_dir}"
with tempfile.TemporaryDirectory() as temp_dir:
temp_content_dir = Path(temp_dir) / "content"
shutil.copytree(input_dir, temp_content_dir)
for pattern in ["*.xml", "*.rels"]:
for xml_file in temp_content_dir.rglob(pattern):
_condense_xml(xml_file)
output_path.parent.mkdir(parents=True, exist_ok=True)
with zipfile.ZipFile(output_path, "w", zipfile.ZIP_DEFLATED) as zf:
for f in temp_content_dir.rglob("*"):
if f.is_file():
zf.write(f, f.relative_to(temp_content_dir))
return None, f"Successfully packed {input_dir} to {output_file}"
def _run_validation(
unpacked_dir: Path,
original_file: Path,
suffix: str,
infer_author_func=None,
) -> tuple[bool, str | None]:
output_lines = []
validators = []
if suffix == ".docx":
author = "Claude"
if infer_author_func:
try:
author = infer_author_func(unpacked_dir, original_file)
except ValueError as e:
print(f"Warning: {e} Using default author 'Claude'.", file=sys.stderr)
validators = [
DOCXSchemaValidator(unpacked_dir, original_file),
RedliningValidator(unpacked_dir, original_file, author=author),
]
elif suffix == ".pptx":
validators = [PPTXSchemaValidator(unpacked_dir, original_file)]
if not validators:
return True, None
total_repairs = sum(v.repair() for v in validators)
if total_repairs:
output_lines.append(f"Auto-repaired {total_repairs} issue(s)")
success = all(v.validate() for v in validators)
if success:
output_lines.append("All validations PASSED!")
return success, "\n".join(output_lines) if output_lines else None
def _condense_xml(xml_file: Path) -> None:
try:
with open(xml_file, encoding="utf-8") as f:
dom = defusedxml.minidom.parse(f)
for element in dom.getElementsByTagName("*"):
if element.tagName.endswith(":t"):
continue
for child in list(element.childNodes):
if (
child.nodeType == child.TEXT_NODE
and child.nodeValue
and child.nodeValue.strip() == ""
) or child.nodeType == child.COMMENT_NODE:
element.removeChild(child)
xml_file.write_bytes(dom.toxml(encoding="UTF-8"))
except Exception as e:
print(f"ERROR: Failed to parse {xml_file.name}: {e}", file=sys.stderr)
raise
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Pack a directory into a DOCX, PPTX, or XLSX file"
)
parser.add_argument("input_directory", help="Unpacked Office document directory")
parser.add_argument("output_file", help="Output Office file (.docx/.pptx/.xlsx)")
parser.add_argument(
"--original",
help="Original file for validation comparison",
)
parser.add_argument(
"--validate",
type=lambda x: x.lower() == "true",
default=True,
metavar="true|false",
help="Run validation with auto-repair (default: true)",
)
args = parser.parse_args()
_, message = pack(
args.input_directory,
args.output_file,
original_file=args.original,
validate=args.validate,
)
print(message)
if "Error" in message:
sys.exit(1)
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xs:schema xmlns="http://schemas.openxmlformats.org/package/2006/content-types"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://schemas.openxmlformats.org/package/2006/content-types"
elementFormDefault="qualified" attributeFormDefault="unqualified" blockDefault="#all">
<xs:element name="Types" type="CT_Types"/>
<xs:element name="Default" type="CT_Default"/>
<xs:element name="Override" type="CT_Override"/>
<xs:complexType name="CT_Types">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="Default"/>
<xs:element ref="Override"/>
</xs:choice>
</xs:complexType>
<xs:complexType name="CT_Default">
<xs:attribute name="Extension" type="ST_Extension" use="required"/>
<xs:attribute name="ContentType" type="ST_ContentType" use="required"/>
</xs:complexType>
<xs:complexType name="CT_Override">
<xs:attribute name="ContentType" type="ST_ContentType" use="required"/>
<xs:attribute name="PartName" type="xs:anyURI" use="required"/>
</xs:complexType>
<xs:simpleType name="ST_ContentType">
<xs:restriction base="xs:string">
<xs:pattern
value="(((([\p{IsBasicLatin}-[\p{Cc}\(\)<>@,;:\\"/\[\]\?=\{\}\s\t]])+))/((([\p{IsBasicLatin}-[\p{Cc}\(\)<>@,;:\\"/\[\]\?=\{\}\s\t]])+))((\s+)*;(\s+)*(((([\p{IsBasicLatin}-[\p{Cc}\(\)<>@,;:\\"/\[\]\?=\{\}\s\t]])+))=((([\p{IsBasicLatin}-[\p{Cc}\(\)<>@,;:\\"/\[\]\?=\{\}\s\t]])+)|("(([\p{IsLatin-1Supplement}\p{IsBasicLatin}-[\p{Cc}"\n\r]]|(\s+))|(\\[\p{IsBasicLatin}]))*"))))*)"
/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="ST_Extension">
<xs:restriction base="xs:string">
<xs:pattern
value="([!$&'\(\)\*\+,:=]|(%[0-9a-fA-F][0-9a-fA-F])|[:@]|[a-zA-Z0-9\-_~])+"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema targetNamespace="http://schemas.openxmlformats.org/package/2006/metadata/core-properties"
xmlns="http://schemas.openxmlformats.org/package/2006/metadata/core-properties"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:dcterms="http://purl.org/dc/terms/" elementFormDefault="qualified" blockDefault="#all">
<xs:import namespace="http://purl.org/dc/elements/1.1/"
schemaLocation="http://dublincore.org/schemas/xmls/qdc/2003/04/02/dc.xsd"/>
<xs:import namespace="http://purl.org/dc/terms/"
schemaLocation="http://dublincore.org/schemas/xmls/qdc/2003/04/02/dcterms.xsd"/>
<xs:import id="xml" namespace="http://www.w3.org/XML/1998/namespace"/>
<xs:element name="coreProperties" type="CT_CoreProperties"/>
<xs:complexType name="CT_CoreProperties">
<xs:all>
<xs:element name="category" minOccurs="0" maxOccurs="1" type="xs:string"/>
<xs:element name="contentStatus" minOccurs="0" maxOccurs="1" type="xs:string"/>
<xs:element ref="dcterms:created" minOccurs="0" maxOccurs="1"/>
<xs:element ref="dc:creator" minOccurs="0" maxOccurs="1"/>
<xs:element ref="dc:description" minOccurs="0" maxOccurs="1"/>
<xs:element ref="dc:identifier" minOccurs="0" maxOccurs="1"/>
<xs:element name="keywords" minOccurs="0" maxOccurs="1" type="CT_Keywords"/>
<xs:element ref="dc:language" minOccurs="0" maxOccurs="1"/>
<xs:element name="lastModifiedBy" minOccurs="0" maxOccurs="1" type="xs:string"/>
<xs:element name="lastPrinted" minOccurs="0" maxOccurs="1" type="xs:dateTime"/>
<xs:element ref="dcterms:modified" minOccurs="0" maxOccurs="1"/>
<xs:element name="revision" minOccurs="0" maxOccurs="1" type="xs:string"/>
<xs:element ref="dc:subject" minOccurs="0" maxOccurs="1"/>
<xs:element ref="dc:title" minOccurs="0" maxOccurs="1"/>
<xs:element name="version" minOccurs="0" maxOccurs="1" type="xs:string"/>
</xs:all>
</xs:complexType>
<xs:complexType name="CT_Keywords" mixed="true">
<xs:sequence>
<xs:element name="value" minOccurs="0" maxOccurs="unbounded" type="CT_Keyword"/>
</xs:sequence>
<xs:attribute ref="xml:lang" use="optional"/>
</xs:complexType>
<xs:complexType name="CT_Keyword">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute ref="xml:lang" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:schema>
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://schemas.openxmlformats.org/package/2006/digital-signature"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://schemas.openxmlformats.org/package/2006/digital-signature"
elementFormDefault="qualified" attributeFormDefault="unqualified" blockDefault="#all">
<xsd:element name="SignatureTime" type="CT_SignatureTime"/>
<xsd:element name="RelationshipReference" type="CT_RelationshipReference"/>
<xsd:element name="RelationshipsGroupReference" type="CT_RelationshipsGroupReference"/>
<xsd:complexType name="CT_SignatureTime">
<xsd:sequence>
<xsd:element name="Format" type="ST_Format"/>
<xsd:element name="Value" type="ST_Value"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_RelationshipReference">
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attribute name="SourceId" type="xsd:string" use="required"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<xsd:complexType name="CT_RelationshipsGroupReference">
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attribute name="SourceType" type="xsd:anyURI" use="required"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<xsd:simpleType name="ST_Format">
<xsd:restriction base="xsd:string">
<xsd:pattern
value="(YYYY)|(YYYY-MM)|(YYYY-MM-DD)|(YYYY-MM-DDThh:mmTZD)|(YYYY-MM-DDThh:mm:ssTZD)|(YYYY-MM-DDThh:mm:ss.sTZD)"
/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_Value">
<xsd:restriction base="xsd:string">
<xsd:pattern
value="(([0-9][0-9][0-9][0-9]))|(([0-9][0-9][0-9][0-9])-((0[1-9])|(1(0|1|2))))|(([0-9][0-9][0-9][0-9])-((0[1-9])|(1(0|1|2)))-((0[1-9])|(1[0-9])|(2[0-9])|(3(0|1))))|(([0-9][0-9][0-9][0-9])-((0[1-9])|(1(0|1|2)))-((0[1-9])|(1[0-9])|(2[0-9])|(3(0|1)))T((0[0-9])|(1[0-9])|(2(0|1|2|3))):((0[0-9])|(1[0-9])|(2[0-9])|(3[0-9])|(4[0-9])|(5[0-9]))(((\+|-)((0[0-9])|(1[0-9])|(2(0|1|2|3))):((0[0-9])|(1[0-9])|(2[0-9])|(3[0-9])|(4[0-9])|(5[0-9])))|Z))|(([0-9][0-9][0-9][0-9])-((0[1-9])|(1(0|1|2)))-((0[1-9])|(1[0-9])|(2[0-9])|(3(0|1)))T((0[0-9])|(1[0-9])|(2(0|1|2|3))):((0[0-9])|(1[0-9])|(2[0-9])|(3[0-9])|(4[0-9])|(5[0-9])):((0[0-9])|(1[0-9])|(2[0-9])|(3[0-9])|(4[0-9])|(5[0-9]))(((\+|-)((0[0-9])|(1[0-9])|(2(0|1|2|3))):((0[0-9])|(1[0-9])|(2[0-9])|(3[0-9])|(4[0-9])|(5[0-9])))|Z))|(([0-9][0-9][0-9][0-9])-((0[1-9])|(1(0|1|2)))-((0[1-9])|(1[0-9])|(2[0-9])|(3(0|1)))T((0[0-9])|(1[0-9])|(2(0|1|2|3))):((0[0-9])|(1[0-9])|(2[0-9])|(3[0-9])|(4[0-9])|(5[0-9])):(((0[0-9])|(1[0-9])|(2[0-9])|(3[0-9])|(4[0-9])|(5[0-9]))\.[0-9])(((\+|-)((0[0-9])|(1[0-9])|(2(0|1|2|3))):((0[0-9])|(1[0-9])|(2[0-9])|(3[0-9])|(4[0-9])|(5[0-9])))|Z))"
/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsd:schema xmlns="http://schemas.openxmlformats.org/package/2006/relationships"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://schemas.openxmlformats.org/package/2006/relationships"
elementFormDefault="qualified" attributeFormDefault="unqualified" blockDefault="#all">
<xsd:element name="Relationships" type="CT_Relationships"/>
<xsd:element name="Relationship" type="CT_Relationship"/>
<xsd:complexType name="CT_Relationships">
<xsd:sequence>
<xsd:element ref="Relationship" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_Relationship">
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attribute name="TargetMode" type="ST_TargetMode" use="optional"/>
<xsd:attribute name="Target" type="xsd:anyURI" use="required"/>
<xsd:attribute name="Type" type="xsd:anyURI" use="required"/>
<xsd:attribute name="Id" type="xsd:ID" use="required"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<xsd:simpleType name="ST_TargetMode">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="External"/>
<xsd:enumeration value="Internal"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
xmlns="http://schemas.openxmlformats.org/drawingml/2006/chartDrawing"
targetNamespace="http://schemas.openxmlformats.org/drawingml/2006/chartDrawing"
elementFormDefault="qualified">
<xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/main"
schemaLocation="dml-main.xsd"/>
<xsd:complexType name="CT_ShapeNonVisual">
<xsd:sequence>
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
<xsd:element name="cNvSpPr" type="a:CT_NonVisualDrawingShapeProps" minOccurs="1" maxOccurs="1"
/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_Shape">
<xsd:sequence>
<xsd:element name="nvSpPr" type="CT_ShapeNonVisual" minOccurs="1" maxOccurs="1"/>
<xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="1" maxOccurs="1"/>
<xsd:element name="style" type="a:CT_ShapeStyle" minOccurs="0" maxOccurs="1"/>
<xsd:element name="txBody" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="macro" type="xsd:string" use="optional"/>
<xsd:attribute name="textlink" type="xsd:string" use="optional"/>
<xsd:attribute name="fLocksText" type="xsd:boolean" use="optional" default="true"/>
<xsd:attribute name="fPublished" type="xsd:boolean" use="optional" default="false"/>
</xsd:complexType>
<xsd:complexType name="CT_ConnectorNonVisual">
<xsd:sequence>
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
<xsd:element name="cNvCxnSpPr" type="a:CT_NonVisualConnectorProperties" minOccurs="1"
maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_Connector">
<xsd:sequence>
<xsd:element name="nvCxnSpPr" type="CT_ConnectorNonVisual" minOccurs="1" maxOccurs="1"/>
<xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="1" maxOccurs="1"/>
<xsd:element name="style" type="a:CT_ShapeStyle" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="macro" type="xsd:string" use="optional"/>
<xsd:attribute name="fPublished" type="xsd:boolean" use="optional" default="false"/>
</xsd:complexType>
<xsd:complexType name="CT_PictureNonVisual">
<xsd:sequence>
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
<xsd:element name="cNvPicPr" type="a:CT_NonVisualPictureProperties" minOccurs="1"
maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_Picture">
<xsd:sequence>
<xsd:element name="nvPicPr" type="CT_PictureNonVisual" minOccurs="1" maxOccurs="1"/>
<xsd:element name="blipFill" type="a:CT_BlipFillProperties" minOccurs="1" maxOccurs="1"/>
<xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="1" maxOccurs="1"/>
<xsd:element name="style" type="a:CT_ShapeStyle" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="macro" type="xsd:string" use="optional" default=""/>
<xsd:attribute name="fPublished" type="xsd:boolean" use="optional" default="false"/>
</xsd:complexType>
<xsd:complexType name="CT_GraphicFrameNonVisual">
<xsd:sequence>
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
<xsd:element name="cNvGraphicFramePr" type="a:CT_NonVisualGraphicFrameProperties"
minOccurs="1" maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_GraphicFrame">
<xsd:sequence>
<xsd:element name="nvGraphicFramePr" type="CT_GraphicFrameNonVisual" minOccurs="1"
maxOccurs="1"/>
<xsd:element name="xfrm" type="a:CT_Transform2D" minOccurs="1" maxOccurs="1"/>
<xsd:element ref="a:graphic" minOccurs="1" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="macro" type="xsd:string" use="optional"/>
<xsd:attribute name="fPublished" type="xsd:boolean" use="optional" default="false"/>
</xsd:complexType>
<xsd:complexType name="CT_GroupShapeNonVisual">
<xsd:sequence>
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
<xsd:element name="cNvGrpSpPr" type="a:CT_NonVisualGroupDrawingShapeProps" minOccurs="1"
maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_GroupShape">
<xsd:sequence>
<xsd:element name="nvGrpSpPr" type="CT_GroupShapeNonVisual" minOccurs="1" maxOccurs="1"/>
<xsd:element name="grpSpPr" type="a:CT_GroupShapeProperties" minOccurs="1" maxOccurs="1"/>
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element name="sp" type="CT_Shape"/>
<xsd:element name="grpSp" type="CT_GroupShape"/>
<xsd:element name="graphicFrame" type="CT_GraphicFrame"/>
<xsd:element name="cxnSp" type="CT_Connector"/>
<xsd:element name="pic" type="CT_Picture"/>
</xsd:choice>
</xsd:sequence>
</xsd:complexType>
<xsd:group name="EG_ObjectChoices">
<xsd:sequence>
<xsd:choice minOccurs="1" maxOccurs="1">
<xsd:element name="sp" type="CT_Shape"/>
<xsd:element name="grpSp" type="CT_GroupShape"/>
<xsd:element name="graphicFrame" type="CT_GraphicFrame"/>
<xsd:element name="cxnSp" type="CT_Connector"/>
<xsd:element name="pic" type="CT_Picture"/>
</xsd:choice>
</xsd:sequence>
</xsd:group>
<xsd:simpleType name="ST_MarkerCoordinate">
<xsd:restriction base="xsd:double">
<xsd:minInclusive value="0.0"/>
<xsd:maxInclusive value="1.0"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="CT_Marker">
<xsd:sequence>
<xsd:element name="x" type="ST_MarkerCoordinate" minOccurs="1" maxOccurs="1"/>
<xsd:element name="y" type="ST_MarkerCoordinate" minOccurs="1" maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_RelSizeAnchor">
<xsd:sequence>
<xsd:element name="from" type="CT_Marker"/>
<xsd:element name="to" type="CT_Marker"/>
<xsd:group ref="EG_ObjectChoices"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_AbsSizeAnchor">
<xsd:sequence>
<xsd:element name="from" type="CT_Marker"/>
<xsd:element name="ext" type="a:CT_PositiveSize2D"/>
<xsd:group ref="EG_ObjectChoices"/>
</xsd:sequence>
</xsd:complexType>
<xsd:group name="EG_Anchor">
<xsd:choice>
<xsd:element name="relSizeAnchor" type="CT_RelSizeAnchor"/>
<xsd:element name="absSizeAnchor" type="CT_AbsSizeAnchor"/>
</xsd:choice>
</xsd:group>
<xsd:complexType name="CT_Drawing">
<xsd:sequence>
<xsd:group ref="EG_Anchor" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.openxmlformats.org/drawingml/2006/diagram"
xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
targetNamespace="http://schemas.openxmlformats.org/drawingml/2006/diagram"
elementFormDefault="qualified" attributeFormDefault="unqualified">
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
schemaLocation="shared-relationshipReference.xsd"/>
<xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/main"
schemaLocation="dml-main.xsd"/>
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
schemaLocation="shared-commonSimpleTypes.xsd"/>
<xsd:complexType name="CT_CTName">
<xsd:attribute name="lang" type="xsd:string" use="optional" default=""/>
<xsd:attribute name="val" type="xsd:string" use="required"/>
</xsd:complexType>
<xsd:complexType name="CT_CTDescription">
<xsd:attribute name="lang" type="xsd:string" use="optional" default=""/>
<xsd:attribute name="val" type="xsd:string" use="required"/>
</xsd:complexType>
<xsd:complexType name="CT_CTCategory">
<xsd:attribute name="type" type="xsd:anyURI" use="required"/>
<xsd:attribute name="pri" type="xsd:unsignedInt" use="required"/>
</xsd:complexType>
<xsd:complexType name="CT_CTCategories">
<xsd:sequence minOccurs="0" maxOccurs="unbounded">
<xsd:element name="cat" type="CT_CTCategory" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:simpleType name="ST_ClrAppMethod">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="span"/>
<xsd:enumeration value="cycle"/>
<xsd:enumeration value="repeat"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_HueDir">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="cw"/>
<xsd:enumeration value="ccw"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="CT_Colors">
<xsd:sequence>
<xsd:group ref="a:EG_ColorChoice" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="meth" type="ST_ClrAppMethod" use="optional" default="span"/>
<xsd:attribute name="hueDir" type="ST_HueDir" use="optional" default="cw"/>
</xsd:complexType>
<xsd:complexType name="CT_CTStyleLabel">
<xsd:sequence>
<xsd:element name="fillClrLst" type="CT_Colors" minOccurs="0" maxOccurs="1"/>
<xsd:element name="linClrLst" type="CT_Colors" minOccurs="0" maxOccurs="1"/>
<xsd:element name="effectClrLst" type="CT_Colors" minOccurs="0" maxOccurs="1"/>
<xsd:element name="txLinClrLst" type="CT_Colors" minOccurs="0" maxOccurs="1"/>
<xsd:element name="txFillClrLst" type="CT_Colors" minOccurs="0" maxOccurs="1"/>
<xsd:element name="txEffectClrLst" type="CT_Colors" minOccurs="0" maxOccurs="1"/>
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
<xsd:complexType name="CT_ColorTransform">
<xsd:sequence>
<xsd:element name="title" type="CT_CTName" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="desc" type="CT_CTDescription" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="catLst" type="CT_CTCategories" minOccurs="0"/>
<xsd:element name="styleLbl" type="CT_CTStyleLabel" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="uniqueId" type="xsd:string" use="optional" default=""/>
<xsd:attribute name="minVer" type="xsd:string" use="optional"/>
</xsd:complexType>
<xsd:element name="colorsDef" type="CT_ColorTransform"/>
<xsd:complexType name="CT_ColorTransformHeader">
<xsd:sequence>
<xsd:element name="title" type="CT_CTName" minOccurs="1" maxOccurs="unbounded"/>
<xsd:element name="desc" type="CT_CTDescription" minOccurs="1" maxOccurs="unbounded"/>
<xsd:element name="catLst" type="CT_CTCategories" minOccurs="0"/>
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="uniqueId" type="xsd:string" use="required"/>
<xsd:attribute name="minVer" type="xsd:string" use="optional"/>
<xsd:attribute name="resId" type="xsd:int" use="optional" default="0"/>
</xsd:complexType>
<xsd:element name="colorsDefHdr" type="CT_ColorTransformHeader"/>
<xsd:complexType name="CT_ColorTransformHeaderLst">
<xsd:sequence>
<xsd:element name="colorsDefHdr" type="CT_ColorTransformHeader" minOccurs="0"
maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="colorsDefHdrLst" type="CT_ColorTransformHeaderLst"/>
<xsd:simpleType name="ST_PtType">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="node"/>
<xsd:enumeration value="asst"/>
<xsd:enumeration value="doc"/>
<xsd:enumeration value="pres"/>
<xsd:enumeration value="parTrans"/>
<xsd:enumeration value="sibTrans"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="CT_Pt">
<xsd:sequence>
<xsd:element name="prSet" type="CT_ElemPropSet" minOccurs="0" maxOccurs="1"/>
<xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="0" maxOccurs="1"/>
<xsd:element name="t" type="a:CT_TextBody" minOccurs="0" maxOccurs="1"/>
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="modelId" type="ST_ModelId" use="required"/>
<xsd:attribute name="type" type="ST_PtType" use="optional" default="node"/>
<xsd:attribute name="cxnId" type="ST_ModelId" use="optional" default="0"/>
</xsd:complexType>
<xsd:complexType name="CT_PtList">
<xsd:sequence>
<xsd:element name="pt" type="CT_Pt" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:simpleType name="ST_CxnType">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="parOf"/>
<xsd:enumeration value="presOf"/>
<xsd:enumeration value="presParOf"/>
<xsd:enumeration value="unknownRelationship"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="CT_Cxn">
<xsd:sequence>
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="modelId" type="ST_ModelId" use="required"/>
<xsd:attribute name="type" type="ST_CxnType" use="optional" default="parOf"/>
<xsd:attribute name="srcId" type="ST_ModelId" use="required"/>
<xsd:attribute name="destId" type="ST_ModelId" use="required"/>
<xsd:attribute name="srcOrd" type="xsd:unsignedInt" use="required"/>
<xsd:attribute name="destOrd" type="xsd:unsignedInt" use="required"/>
<xsd:attribute name="parTransId" type="ST_ModelId" use="optional" default="0"/>
<xsd:attribute name="sibTransId" type="ST_ModelId" use="optional" default="0"/>
<xsd:attribute name="presId" type="xsd:string" use="optional" default=""/>
</xsd:complexType>
<xsd:complexType name="CT_CxnList">
<xsd:sequence>
<xsd:element name="cxn" type="CT_Cxn" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_DataModel">
<xsd:sequence>
<xsd:element name="ptLst" type="CT_PtList"/>
<xsd:element name="cxnLst" type="CT_CxnList" minOccurs="0" maxOccurs="1"/>
<xsd:element name="bg" type="a:CT_BackgroundFormatting" minOccurs="0"/>
<xsd:element name="whole" type="a:CT_WholeE2oFormatting" minOccurs="0"/>
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="dataModel" type="CT_DataModel"/>
<xsd:attributeGroup name="AG_IteratorAttributes">
<xsd:attribute name="axis" type="ST_AxisTypes" use="optional" default="none"/>
<xsd:attribute name="ptType" type="ST_ElementTypes" use="optional" default="all"/>
<xsd:attribute name="hideLastTrans" type="ST_Booleans" use="optional" default="true"/>
<xsd:attribute name="st" type="ST_Ints" use="optional" default="1"/>
<xsd:attribute name="cnt" type="ST_UnsignedInts" use="optional" default="0"/>
<xsd:attribute name="step" type="ST_Ints" use="optional" default="1"/>
</xsd:attributeGroup>
<xsd:attributeGroup name="AG_ConstraintAttributes">
<xsd:attribute name="type" type="ST_ConstraintType" use="required"/>
<xsd:attribute name="for" type="ST_ConstraintRelationship" use="optional" default="self"/>
<xsd:attribute name="forName" type="xsd:string" use="optional" default=""/>
<xsd:attribute name="ptType" type="ST_ElementType" use="optional" default="all"/>
</xsd:attributeGroup>
<xsd:attributeGroup name="AG_ConstraintRefAttributes">
<xsd:attribute name="refType" type="ST_ConstraintType" use="optional" default="none"/>
<xsd:attribute name="refFor" type="ST_ConstraintRelationship" use="optional" default="self"/>
<xsd:attribute name="refForName" type="xsd:string" use="optional" default=""/>
<xsd:attribute name="refPtType" type="ST_ElementType" use="optional" default="all"/>
</xsd:attributeGroup>
<xsd:complexType name="CT_Constraint">
<xsd:sequence>
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attributeGroup ref="AG_ConstraintAttributes"/>
<xsd:attributeGroup ref="AG_ConstraintRefAttributes"/>
<xsd:attribute name="op" type="ST_BoolOperator" use="optional" default="none"/>
<xsd:attribute name="val" type="xsd:double" use="optional" default="0"/>
<xsd:attribute name="fact" type="xsd:double" use="optional" default="1"/>
</xsd:complexType>
<xsd:complexType name="CT_Constraints">
<xsd:sequence>
<xsd:element name="constr" type="CT_Constraint" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_NumericRule">
<xsd:sequence>
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attributeGroup ref="AG_ConstraintAttributes"/>
<xsd:attribute name="val" type="xsd:double" use="optional" default="NaN"/>
<xsd:attribute name="fact" type="xsd:double" use="optional" default="NaN"/>
<xsd:attribute name="max" type="xsd:double" use="optional" default="NaN"/>
</xsd:complexType>
<xsd:complexType name="CT_Rules">
<xsd:sequence>
<xsd:element name="rule" type="CT_NumericRule" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_PresentationOf">
<xsd:sequence>
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attributeGroup ref="AG_IteratorAttributes"/>
</xsd:complexType>
<xsd:simpleType name="ST_LayoutShapeType" final="restriction">
<xsd:union memberTypes="a:ST_ShapeType ST_OutputShapeType"/>
</xsd:simpleType>
<xsd:simpleType name="ST_Index1">
<xsd:restriction base="xsd:unsignedInt">
<xsd:minInclusive value="1"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="CT_Adj">
<xsd:attribute name="idx" type="ST_Index1" use="required"/>
<xsd:attribute name="val" type="xsd:double" use="required"/>
</xsd:complexType>
<xsd:complexType name="CT_AdjLst">
<xsd:sequence>
<xsd:element name="adj" type="CT_Adj" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_Shape">
<xsd:sequence>
<xsd:element name="adjLst" type="CT_AdjLst" minOccurs="0" maxOccurs="1"/>
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="rot" type="xsd:double" use="optional" default="0"/>
<xsd:attribute name="type" type="ST_LayoutShapeType" use="optional" default="none"/>
<xsd:attribute ref="r:blip" use="optional"/>
<xsd:attribute name="zOrderOff" type="xsd:int" use="optional" default="0"/>
<xsd:attribute name="hideGeom" type="xsd:boolean" use="optional" default="false"/>
<xsd:attribute name="lkTxEntry" type="xsd:boolean" use="optional" default="false"/>
<xsd:attribute name="blipPhldr" type="xsd:boolean" use="optional" default="false"/>
</xsd:complexType>
<xsd:complexType name="CT_Parameter">
<xsd:attribute name="type" type="ST_ParameterId" use="required"/>
<xsd:attribute name="val" type="ST_ParameterVal" use="required"/>
</xsd:complexType>
<xsd:complexType name="CT_Algorithm">
<xsd:sequence>
<xsd:element name="param" type="CT_Parameter" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="type" type="ST_AlgorithmType" use="required"/>
<xsd:attribute name="rev" type="xsd:unsignedInt" use="optional" default="0"/>
</xsd:complexType>
<xsd:complexType name="CT_LayoutNode">
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element name="alg" type="CT_Algorithm" minOccurs="0" maxOccurs="1"/>
<xsd:element name="shape" type="CT_Shape" minOccurs="0" maxOccurs="1"/>
<xsd:element name="presOf" type="CT_PresentationOf" minOccurs="0" maxOccurs="1"/>
<xsd:element name="constrLst" type="CT_Constraints" minOccurs="0" maxOccurs="1"/>
<xsd:element name="ruleLst" type="CT_Rules" minOccurs="0" maxOccurs="1"/>
<xsd:element name="varLst" type="CT_LayoutVariablePropertySet" minOccurs="0" maxOccurs="1"/>
<xsd:element name="forEach" type="CT_ForEach"/>
<xsd:element name="layoutNode" type="CT_LayoutNode"/>
<xsd:element name="choose" type="CT_Choose"/>
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
</xsd:choice>
<xsd:attribute name="name" type="xsd:string" use="optional" default=""/>
<xsd:attribute name="styleLbl" type="xsd:string" use="optional" default=""/>
<xsd:attribute name="chOrder" type="ST_ChildOrderType" use="optional" default="b"/>
<xsd:attribute name="moveWith" type="xsd:string" use="optional" default=""/>
</xsd:complexType>
<xsd:complexType name="CT_ForEach">
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element name="alg" type="CT_Algorithm" minOccurs="0" maxOccurs="1"/>
<xsd:element name="shape" type="CT_Shape" minOccurs="0" maxOccurs="1"/>
<xsd:element name="presOf" type="CT_PresentationOf" minOccurs="0" maxOccurs="1"/>
<xsd:element name="constrLst" type="CT_Constraints" minOccurs="0" maxOccurs="1"/>
<xsd:element name="ruleLst" type="CT_Rules" minOccurs="0" maxOccurs="1"/>
<xsd:element name="forEach" type="CT_ForEach"/>
<xsd:element name="layoutNode" type="CT_LayoutNode"/>
<xsd:element name="choose" type="CT_Choose"/>
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
</xsd:choice>
<xsd:attribute name="name" type="xsd:string" use="optional" default=""/>
<xsd:attribute name="ref" type="xsd:string" use="optional" default=""/>
<xsd:attributeGroup ref="AG_IteratorAttributes"/>
</xsd:complexType>
<xsd:complexType name="CT_When">
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element name="alg" type="CT_Algorithm" minOccurs="0" maxOccurs="1"/>
<xsd:element name="shape" type="CT_Shape" minOccurs="0" maxOccurs="1"/>
<xsd:element name="presOf" type="CT_PresentationOf" minOccurs="0" maxOccurs="1"/>
<xsd:element name="constrLst" type="CT_Constraints" minOccurs="0" maxOccurs="1"/>
<xsd:element name="ruleLst" type="CT_Rules" minOccurs="0" maxOccurs="1"/>
<xsd:element name="forEach" type="CT_ForEach"/>
<xsd:element name="layoutNode" type="CT_LayoutNode"/>
<xsd:element name="choose" type="CT_Choose"/>
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
</xsd:choice>
<xsd:attribute name="name" type="xsd:string" use="optional" default=""/>
<xsd:attributeGroup ref="AG_IteratorAttributes"/>
<xsd:attribute name="func" type="ST_FunctionType" use="required"/>
<xsd:attribute name="arg" type="ST_FunctionArgument" use="optional" default="none"/>
<xsd:attribute name="op" type="ST_FunctionOperator" use="required"/>
<xsd:attribute name="val" type="ST_FunctionValue" use="required"/>
</xsd:complexType>
<xsd:complexType name="CT_Otherwise">
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element name="alg" type="CT_Algorithm" minOccurs="0" maxOccurs="1"/>
<xsd:element name="shape" type="CT_Shape" minOccurs="0" maxOccurs="1"/>
<xsd:element name="presOf" type="CT_PresentationOf" minOccurs="0" maxOccurs="1"/>
<xsd:element name="constrLst" type="CT_Constraints" minOccurs="0" maxOccurs="1"/>
<xsd:element name="ruleLst" type="CT_Rules" minOccurs="0" maxOccurs="1"/>
<xsd:element name="forEach" type="CT_ForEach"/>
<xsd:element name="layoutNode" type="CT_LayoutNode"/>
<xsd:element name="choose" type="CT_Choose"/>
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
</xsd:choice>
<xsd:attribute name="name" type="xsd:string" use="optional" default=""/>
</xsd:complexType>
<xsd:complexType name="CT_Choose">
<xsd:sequence>
<xsd:element name="if" type="CT_When" maxOccurs="unbounded"/>
<xsd:element name="else" type="CT_Otherwise" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="optional" default=""/>
</xsd:complexType>
<xsd:complexType name="CT_SampleData">
<xsd:sequence>
<xsd:element name="dataModel" type="CT_DataModel" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="useDef" type="xsd:boolean" use="optional" default="false"/>
</xsd:complexType>
<xsd:complexType name="CT_Category">
<xsd:attribute name="type" type="xsd:anyURI" use="required"/>
<xsd:attribute name="pri" type="xsd:unsignedInt" use="required"/>
</xsd:complexType>
<xsd:complexType name="CT_Categories">
<xsd:sequence>
<xsd:element name="cat" type="CT_Category" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_Name">
<xsd:attribute name="lang" type="xsd:string" use="optional" default=""/>
<xsd:attribute name="val" type="xsd:string" use="required"/>
</xsd:complexType>
<xsd:complexType name="CT_Description">
<xsd:attribute name="lang" type="xsd:string" use="optional" default=""/>
<xsd:attribute name="val" type="xsd:string" use="required"/>
</xsd:complexType>
<xsd:complexType name="CT_DiagramDefinition">
<xsd:sequence>
<xsd:element name="title" type="CT_Name" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="desc" type="CT_Description" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="catLst" type="CT_Categories" minOccurs="0"/>
<xsd:element name="sampData" type="CT_SampleData" minOccurs="0"/>
<xsd:element name="styleData" type="CT_SampleData" minOccurs="0"/>
<xsd:element name="clrData" type="CT_SampleData" minOccurs="0"/>
<xsd:element name="layoutNode" type="CT_LayoutNode"/>
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="uniqueId" type="xsd:string" use="optional" default=""/>
<xsd:attribute name="minVer" type="xsd:string" use="optional"/>
<xsd:attribute name="defStyle" type="xsd:string" use="optional" default=""/>
</xsd:complexType>
<xsd:element name="layoutDef" type="CT_DiagramDefinition"/>
<xsd:complexType name="CT_DiagramDefinitionHeader">
<xsd:sequence>
<xsd:element name="title" type="CT_Name" minOccurs="1" maxOccurs="unbounded"/>
<xsd:element name="desc" type="CT_Description" minOccurs="1" maxOccurs="unbounded"/>
<xsd:element name="catLst" type="CT_Categories" minOccurs="0"/>
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="uniqueId" type="xsd:string" use="required"/>
<xsd:attribute name="minVer" type="xsd:string" use="optional"/>
<xsd:attribute name="defStyle" type="xsd:string" use="optional" default=""/>
<xsd:attribute name="resId" type="xsd:int" use="optional" default="0"/>
</xsd:complexType>
<xsd:element name="layoutDefHdr" type="CT_DiagramDefinitionHeader"/>
<xsd:complexType name="CT_DiagramDefinitionHeaderLst">
<xsd:sequence>
<xsd:element name="layoutDefHdr" type="CT_DiagramDefinitionHeader" minOccurs="0"
maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="layoutDefHdrLst" type="CT_DiagramDefinitionHeaderLst"/>
<xsd:complexType name="CT_RelIds">
<xsd:attribute ref="r:dm" use="required"/>
<xsd:attribute ref="r:lo" use="required"/>
<xsd:attribute ref="r:qs" use="required"/>
<xsd:attribute ref="r:cs" use="required"/>
</xsd:complexType>
<xsd:element name="relIds" type="CT_RelIds"/>
<xsd:simpleType name="ST_ParameterVal">
<xsd:union
memberTypes="ST_DiagramHorizontalAlignment ST_VerticalAlignment ST_ChildDirection ST_ChildAlignment ST_SecondaryChildAlignment ST_LinearDirection ST_SecondaryLinearDirection ST_StartingElement ST_BendPoint ST_ConnectorRouting ST_ArrowheadStyle ST_ConnectorDimension ST_RotationPath ST_CenterShapeMapping ST_NodeHorizontalAlignment ST_NodeVerticalAlignment ST_FallbackDimension ST_TextDirection ST_PyramidAccentPosition ST_PyramidAccentTextMargin ST_TextBlockDirection ST_TextAnchorHorizontal ST_TextAnchorVertical ST_DiagramTextAlignment ST_AutoTextRotation ST_GrowDirection ST_FlowDirection ST_ContinueDirection ST_Breakpoint ST_Offset ST_HierarchyAlignment xsd:int xsd:double xsd:boolean xsd:string ST_ConnectorPoint"
/>
</xsd:simpleType>
<xsd:simpleType name="ST_ModelId">
<xsd:union memberTypes="xsd:int s:ST_Guid"/>
</xsd:simpleType>
<xsd:simpleType name="ST_PrSetCustVal">
<xsd:union memberTypes="s:ST_Percentage xsd:int"/>
</xsd:simpleType>
<xsd:complexType name="CT_ElemPropSet">
<xsd:sequence>
<xsd:element name="presLayoutVars" type="CT_LayoutVariablePropertySet" minOccurs="0"
maxOccurs="1"/>
<xsd:element name="style" type="a:CT_ShapeStyle" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="presAssocID" type="ST_ModelId" use="optional"/>
<xsd:attribute name="presName" type="xsd:string" use="optional"/>
<xsd:attribute name="presStyleLbl" type="xsd:string" use="optional"/>
<xsd:attribute name="presStyleIdx" type="xsd:int" use="optional"/>
<xsd:attribute name="presStyleCnt" type="xsd:int" use="optional"/>
<xsd:attribute name="loTypeId" type="xsd:string" use="optional"/>
<xsd:attribute name="loCatId" type="xsd:string" use="optional"/>
<xsd:attribute name="qsTypeId" type="xsd:string" use="optional"/>
<xsd:attribute name="qsCatId" type="xsd:string" use="optional"/>
<xsd:attribute name="csTypeId" type="xsd:string" use="optional"/>
<xsd:attribute name="csCatId" type="xsd:string" use="optional"/>
<xsd:attribute name="coherent3DOff" type="xsd:boolean" use="optional"/>
<xsd:attribute name="phldrT" type="xsd:string" use="optional"/>
<xsd:attribute name="phldr" type="xsd:boolean" use="optional"/>
<xsd:attribute name="custAng" type="xsd:int" use="optional"/>
<xsd:attribute name="custFlipVert" type="xsd:boolean" use="optional"/>
<xsd:attribute name="custFlipHor" type="xsd:boolean" use="optional"/>
<xsd:attribute name="custSzX" type="xsd:int" use="optional"/>
<xsd:attribute name="custSzY" type="xsd:int" use="optional"/>
<xsd:attribute name="custScaleX" type="ST_PrSetCustVal" use="optional"/>
<xsd:attribute name="custScaleY" type="ST_PrSetCustVal" use="optional"/>
<xsd:attribute name="custT" type="xsd:boolean" use="optional"/>
<xsd:attribute name="custLinFactX" type="ST_PrSetCustVal" use="optional"/>
<xsd:attribute name="custLinFactY" type="ST_PrSetCustVal" use="optional"/>
<xsd:attribute name="custLinFactNeighborX" type="ST_PrSetCustVal" use="optional"/>
<xsd:attribute name="custLinFactNeighborY" type="ST_PrSetCustVal" use="optional"/>
<xsd:attribute name="custRadScaleRad" type="ST_PrSetCustVal" use="optional"/>
<xsd:attribute name="custRadScaleInc" type="ST_PrSetCustVal" use="optional"/>
</xsd:complexType>
<xsd:simpleType name="ST_Direction" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="norm"/>
<xsd:enumeration value="rev"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_HierBranchStyle" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="l"/>
<xsd:enumeration value="r"/>
<xsd:enumeration value="hang"/>
<xsd:enumeration value="std"/>
<xsd:enumeration value="init"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_AnimOneStr" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="none"/>
<xsd:enumeration value="one"/>
<xsd:enumeration value="branch"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_AnimLvlStr" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="none"/>
<xsd:enumeration value="lvl"/>
<xsd:enumeration value="ctr"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="CT_OrgChart">
<xsd:attribute name="val" type="xsd:boolean" default="false" use="optional"/>
</xsd:complexType>
<xsd:simpleType name="ST_NodeCount">
<xsd:restriction base="xsd:int">
<xsd:minInclusive value="-1"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="CT_ChildMax">
<xsd:attribute name="val" type="ST_NodeCount" default="-1" use="optional"/>
</xsd:complexType>
<xsd:complexType name="CT_ChildPref">
<xsd:attribute name="val" type="ST_NodeCount" default="-1" use="optional"/>
</xsd:complexType>
<xsd:complexType name="CT_BulletEnabled">
<xsd:attribute name="val" type="xsd:boolean" default="false" use="optional"/>
</xsd:complexType>
<xsd:complexType name="CT_Direction">
<xsd:attribute name="val" type="ST_Direction" default="norm" use="optional"/>
</xsd:complexType>
<xsd:complexType name="CT_HierBranchStyle">
<xsd:attribute name="val" type="ST_HierBranchStyle" default="std" use="optional"/>
</xsd:complexType>
<xsd:complexType name="CT_AnimOne">
<xsd:attribute name="val" type="ST_AnimOneStr" default="one" use="optional"/>
</xsd:complexType>
<xsd:complexType name="CT_AnimLvl">
<xsd:attribute name="val" type="ST_AnimLvlStr" default="none" use="optional"/>
</xsd:complexType>
<xsd:simpleType name="ST_ResizeHandlesStr" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="exact"/>
<xsd:enumeration value="rel"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="CT_ResizeHandles">
<xsd:attribute name="val" type="ST_ResizeHandlesStr" default="rel" use="optional"/>
</xsd:complexType>
<xsd:complexType name="CT_LayoutVariablePropertySet">
<xsd:sequence>
<xsd:element name="orgChart" type="CT_OrgChart" minOccurs="0" maxOccurs="1"/>
<xsd:element name="chMax" type="CT_ChildMax" minOccurs="0" maxOccurs="1"/>
<xsd:element name="chPref" type="CT_ChildPref" minOccurs="0" maxOccurs="1"/>
<xsd:element name="bulletEnabled" type="CT_BulletEnabled" minOccurs="0" maxOccurs="1"/>
<xsd:element name="dir" type="CT_Direction" minOccurs="0" maxOccurs="1"/>
<xsd:element name="hierBranch" type="CT_HierBranchStyle" minOccurs="0" maxOccurs="1"/>
<xsd:element name="animOne" type="CT_AnimOne" minOccurs="0" maxOccurs="1"/>
<xsd:element name="animLvl" type="CT_AnimLvl" minOccurs="0" maxOccurs="1"/>
<xsd:element name="resizeHandles" type="CT_ResizeHandles" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_SDName">
<xsd:attribute name="lang" type="xsd:string" use="optional" default=""/>
<xsd:attribute name="val" type="xsd:string" use="required"/>
</xsd:complexType>
<xsd:complexType name="CT_SDDescription">
<xsd:attribute name="lang" type="xsd:string" use="optional" default=""/>
<xsd:attribute name="val" type="xsd:string" use="required"/>
</xsd:complexType>
<xsd:complexType name="CT_SDCategory">
<xsd:attribute name="type" type="xsd:anyURI" use="required"/>
<xsd:attribute name="pri" type="xsd:unsignedInt" use="required"/>
</xsd:complexType>
<xsd:complexType name="CT_SDCategories">
<xsd:sequence minOccurs="0" maxOccurs="unbounded">
<xsd:element name="cat" type="CT_SDCategory" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_TextProps">
<xsd:sequence>
<xsd:group ref="a:EG_Text3D" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_StyleLabel">
<xsd:sequence>
<xsd:element name="scene3d" type="a:CT_Scene3D" minOccurs="0" maxOccurs="1"/>
<xsd:element name="sp3d" type="a:CT_Shape3D" minOccurs="0" maxOccurs="1"/>
<xsd:element name="txPr" type="CT_TextProps" minOccurs="0" maxOccurs="1"/>
<xsd:element name="style" type="a:CT_ShapeStyle" minOccurs="0" maxOccurs="1"/>
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
<xsd:complexType name="CT_StyleDefinition">
<xsd:sequence>
<xsd:element name="title" type="CT_SDName" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="desc" type="CT_SDDescription" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="catLst" type="CT_SDCategories" minOccurs="0"/>
<xsd:element name="scene3d" type="a:CT_Scene3D" minOccurs="0" maxOccurs="1"/>
<xsd:element name="styleLbl" type="CT_StyleLabel" minOccurs="1" maxOccurs="unbounded"/>
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="uniqueId" type="xsd:string" use="optional" default=""/>
<xsd:attribute name="minVer" type="xsd:string" use="optional"/>
</xsd:complexType>
<xsd:element name="styleDef" type="CT_StyleDefinition"/>
<xsd:complexType name="CT_StyleDefinitionHeader">
<xsd:sequence>
<xsd:element name="title" type="CT_SDName" minOccurs="1" maxOccurs="unbounded"/>
<xsd:element name="desc" type="CT_SDDescription" minOccurs="1" maxOccurs="unbounded"/>
<xsd:element name="catLst" type="CT_SDCategories" minOccurs="0"/>
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="uniqueId" type="xsd:string" use="required"/>
<xsd:attribute name="minVer" type="xsd:string" use="optional"/>
<xsd:attribute name="resId" type="xsd:int" use="optional" default="0"/>
</xsd:complexType>
<xsd:element name="styleDefHdr" type="CT_StyleDefinitionHeader"/>
<xsd:complexType name="CT_StyleDefinitionHeaderLst">
<xsd:sequence>
<xsd:element name="styleDefHdr" type="CT_StyleDefinitionHeader" minOccurs="0"
maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="styleDefHdrLst" type="CT_StyleDefinitionHeaderLst"/>
<xsd:simpleType name="ST_AlgorithmType" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="composite"/>
<xsd:enumeration value="conn"/>
<xsd:enumeration value="cycle"/>
<xsd:enumeration value="hierChild"/>
<xsd:enumeration value="hierRoot"/>
<xsd:enumeration value="pyra"/>
<xsd:enumeration value="lin"/>
<xsd:enumeration value="sp"/>
<xsd:enumeration value="tx"/>
<xsd:enumeration value="snake"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_AxisType" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="self"/>
<xsd:enumeration value="ch"/>
<xsd:enumeration value="des"/>
<xsd:enumeration value="desOrSelf"/>
<xsd:enumeration value="par"/>
<xsd:enumeration value="ancst"/>
<xsd:enumeration value="ancstOrSelf"/>
<xsd:enumeration value="followSib"/>
<xsd:enumeration value="precedSib"/>
<xsd:enumeration value="follow"/>
<xsd:enumeration value="preced"/>
<xsd:enumeration value="root"/>
<xsd:enumeration value="none"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_AxisTypes">
<xsd:list itemType="ST_AxisType"/>
</xsd:simpleType>
<xsd:simpleType name="ST_BoolOperator" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="none"/>
<xsd:enumeration value="equ"/>
<xsd:enumeration value="gte"/>
<xsd:enumeration value="lte"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_ChildOrderType" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="b"/>
<xsd:enumeration value="t"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_ConstraintType" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="none"/>
<xsd:enumeration value="alignOff"/>
<xsd:enumeration value="begMarg"/>
<xsd:enumeration value="bendDist"/>
<xsd:enumeration value="begPad"/>
<xsd:enumeration value="b"/>
<xsd:enumeration value="bMarg"/>
<xsd:enumeration value="bOff"/>
<xsd:enumeration value="ctrX"/>
<xsd:enumeration value="ctrXOff"/>
<xsd:enumeration value="ctrY"/>
<xsd:enumeration value="ctrYOff"/>
<xsd:enumeration value="connDist"/>
<xsd:enumeration value="diam"/>
<xsd:enumeration value="endMarg"/>
<xsd:enumeration value="endPad"/>
<xsd:enumeration value="h"/>
<xsd:enumeration value="hArH"/>
<xsd:enumeration value="hOff"/>
<xsd:enumeration value="l"/>
<xsd:enumeration value="lMarg"/>
<xsd:enumeration value="lOff"/>
<xsd:enumeration value="r"/>
<xsd:enumeration value="rMarg"/>
<xsd:enumeration value="rOff"/>
<xsd:enumeration value="primFontSz"/>
<xsd:enumeration value="pyraAcctRatio"/>
<xsd:enumeration value="secFontSz"/>
<xsd:enumeration value="sibSp"/>
<xsd:enumeration value="secSibSp"/>
<xsd:enumeration value="sp"/>
<xsd:enumeration value="stemThick"/>
<xsd:enumeration value="t"/>
<xsd:enumeration value="tMarg"/>
<xsd:enumeration value="tOff"/>
<xsd:enumeration value="userA"/>
<xsd:enumeration value="userB"/>
<xsd:enumeration value="userC"/>
<xsd:enumeration value="userD"/>
<xsd:enumeration value="userE"/>
<xsd:enumeration value="userF"/>
<xsd:enumeration value="userG"/>
<xsd:enumeration value="userH"/>
<xsd:enumeration value="userI"/>
<xsd:enumeration value="userJ"/>
<xsd:enumeration value="userK"/>
<xsd:enumeration value="userL"/>
<xsd:enumeration value="userM"/>
<xsd:enumeration value="userN"/>
<xsd:enumeration value="userO"/>
<xsd:enumeration value="userP"/>
<xsd:enumeration value="userQ"/>
<xsd:enumeration value="userR"/>
<xsd:enumeration value="userS"/>
<xsd:enumeration value="userT"/>
<xsd:enumeration value="userU"/>
<xsd:enumeration value="userV"/>
<xsd:enumeration value="userW"/>
<xsd:enumeration value="userX"/>
<xsd:enumeration value="userY"/>
<xsd:enumeration value="userZ"/>
<xsd:enumeration value="w"/>
<xsd:enumeration value="wArH"/>
<xsd:enumeration value="wOff"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_ConstraintRelationship" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="self"/>
<xsd:enumeration value="ch"/>
<xsd:enumeration value="des"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_ElementType" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="all"/>
<xsd:enumeration value="doc"/>
<xsd:enumeration value="node"/>
<xsd:enumeration value="norm"/>
<xsd:enumeration value="nonNorm"/>
<xsd:enumeration value="asst"/>
<xsd:enumeration value="nonAsst"/>
<xsd:enumeration value="parTrans"/>
<xsd:enumeration value="pres"/>
<xsd:enumeration value="sibTrans"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_ElementTypes">
<xsd:list itemType="ST_ElementType"/>
</xsd:simpleType>
<xsd:simpleType name="ST_ParameterId" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="horzAlign"/>
<xsd:enumeration value="vertAlign"/>
<xsd:enumeration value="chDir"/>
<xsd:enumeration value="chAlign"/>
<xsd:enumeration value="secChAlign"/>
<xsd:enumeration value="linDir"/>
<xsd:enumeration value="secLinDir"/>
<xsd:enumeration value="stElem"/>
<xsd:enumeration value="bendPt"/>
<xsd:enumeration value="connRout"/>
<xsd:enumeration value="begSty"/>
<xsd:enumeration value="endSty"/>
<xsd:enumeration value="dim"/>
<xsd:enumeration value="rotPath"/>
<xsd:enumeration value="ctrShpMap"/>
<xsd:enumeration value="nodeHorzAlign"/>
<xsd:enumeration value="nodeVertAlign"/>
<xsd:enumeration value="fallback"/>
<xsd:enumeration value="txDir"/>
<xsd:enumeration value="pyraAcctPos"/>
<xsd:enumeration value="pyraAcctTxMar"/>
<xsd:enumeration value="txBlDir"/>
<xsd:enumeration value="txAnchorHorz"/>
<xsd:enumeration value="txAnchorVert"/>
<xsd:enumeration value="txAnchorHorzCh"/>
<xsd:enumeration value="txAnchorVertCh"/>
<xsd:enumeration value="parTxLTRAlign"/>
<xsd:enumeration value="parTxRTLAlign"/>
<xsd:enumeration value="shpTxLTRAlignCh"/>
<xsd:enumeration value="shpTxRTLAlignCh"/>
<xsd:enumeration value="autoTxRot"/>
<xsd:enumeration value="grDir"/>
<xsd:enumeration value="flowDir"/>
<xsd:enumeration value="contDir"/>
<xsd:enumeration value="bkpt"/>
<xsd:enumeration value="off"/>
<xsd:enumeration value="hierAlign"/>
<xsd:enumeration value="bkPtFixedVal"/>
<xsd:enumeration value="stBulletLvl"/>
<xsd:enumeration value="stAng"/>
<xsd:enumeration value="spanAng"/>
<xsd:enumeration value="ar"/>
<xsd:enumeration value="lnSpPar"/>
<xsd:enumeration value="lnSpAfParP"/>
<xsd:enumeration value="lnSpCh"/>
<xsd:enumeration value="lnSpAfChP"/>
<xsd:enumeration value="rtShortDist"/>
<xsd:enumeration value="alignTx"/>
<xsd:enumeration value="pyraLvlNode"/>
<xsd:enumeration value="pyraAcctBkgdNode"/>
<xsd:enumeration value="pyraAcctTxNode"/>
<xsd:enumeration value="srcNode"/>
<xsd:enumeration value="dstNode"/>
<xsd:enumeration value="begPts"/>
<xsd:enumeration value="endPts"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_Ints">
<xsd:list itemType="xsd:int"/>
</xsd:simpleType>
<xsd:simpleType name="ST_UnsignedInts">
<xsd:list itemType="xsd:unsignedInt"/>
</xsd:simpleType>
<xsd:simpleType name="ST_Booleans">
<xsd:list itemType="xsd:boolean"/>
</xsd:simpleType>
<xsd:simpleType name="ST_FunctionType" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="cnt"/>
<xsd:enumeration value="pos"/>
<xsd:enumeration value="revPos"/>
<xsd:enumeration value="posEven"/>
<xsd:enumeration value="posOdd"/>
<xsd:enumeration value="var"/>
<xsd:enumeration value="depth"/>
<xsd:enumeration value="maxDepth"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_FunctionOperator" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="equ"/>
<xsd:enumeration value="neq"/>
<xsd:enumeration value="gt"/>
<xsd:enumeration value="lt"/>
<xsd:enumeration value="gte"/>
<xsd:enumeration value="lte"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_DiagramHorizontalAlignment" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="l"/>
<xsd:enumeration value="ctr"/>
<xsd:enumeration value="r"/>
<xsd:enumeration value="none"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_VerticalAlignment" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="t"/>
<xsd:enumeration value="mid"/>
<xsd:enumeration value="b"/>
<xsd:enumeration value="none"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_ChildDirection" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="horz"/>
<xsd:enumeration value="vert"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_ChildAlignment" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="t"/>
<xsd:enumeration value="b"/>
<xsd:enumeration value="l"/>
<xsd:enumeration value="r"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_SecondaryChildAlignment" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="none"/>
<xsd:enumeration value="t"/>
<xsd:enumeration value="b"/>
<xsd:enumeration value="l"/>
<xsd:enumeration value="r"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_LinearDirection" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="fromL"/>
<xsd:enumeration value="fromR"/>
<xsd:enumeration value="fromT"/>
<xsd:enumeration value="fromB"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_SecondaryLinearDirection" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="none"/>
<xsd:enumeration value="fromL"/>
<xsd:enumeration value="fromR"/>
<xsd:enumeration value="fromT"/>
<xsd:enumeration value="fromB"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_StartingElement" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="node"/>
<xsd:enumeration value="trans"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_RotationPath" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="none"/>
<xsd:enumeration value="alongPath"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_CenterShapeMapping" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="none"/>
<xsd:enumeration value="fNode"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_BendPoint" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="beg"/>
<xsd:enumeration value="def"/>
<xsd:enumeration value="end"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_ConnectorRouting" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="stra"/>
<xsd:enumeration value="bend"/>
<xsd:enumeration value="curve"/>
<xsd:enumeration value="longCurve"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_ArrowheadStyle" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="auto"/>
<xsd:enumeration value="arr"/>
<xsd:enumeration value="noArr"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_ConnectorDimension" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="1D"/>
<xsd:enumeration value="2D"/>
<xsd:enumeration value="cust"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_ConnectorPoint" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="auto"/>
<xsd:enumeration value="bCtr"/>
<xsd:enumeration value="ctr"/>
<xsd:enumeration value="midL"/>
<xsd:enumeration value="midR"/>
<xsd:enumeration value="tCtr"/>
<xsd:enumeration value="bL"/>
<xsd:enumeration value="bR"/>
<xsd:enumeration value="tL"/>
<xsd:enumeration value="tR"/>
<xsd:enumeration value="radial"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_NodeHorizontalAlignment" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="l"/>
<xsd:enumeration value="ctr"/>
<xsd:enumeration value="r"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_NodeVerticalAlignment" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="t"/>
<xsd:enumeration value="mid"/>
<xsd:enumeration value="b"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_FallbackDimension" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="1D"/>
<xsd:enumeration value="2D"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_TextDirection" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="fromT"/>
<xsd:enumeration value="fromB"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_PyramidAccentPosition" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="bef"/>
<xsd:enumeration value="aft"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_PyramidAccentTextMargin" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="step"/>
<xsd:enumeration value="stack"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_TextBlockDirection" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="horz"/>
<xsd:enumeration value="vert"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_TextAnchorHorizontal" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="none"/>
<xsd:enumeration value="ctr"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_TextAnchorVertical" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="t"/>
<xsd:enumeration value="mid"/>
<xsd:enumeration value="b"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_DiagramTextAlignment" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="l"/>
<xsd:enumeration value="ctr"/>
<xsd:enumeration value="r"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_AutoTextRotation" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="none"/>
<xsd:enumeration value="upr"/>
<xsd:enumeration value="grav"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_GrowDirection" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="tL"/>
<xsd:enumeration value="tR"/>
<xsd:enumeration value="bL"/>
<xsd:enumeration value="bR"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_FlowDirection" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="row"/>
<xsd:enumeration value="col"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_ContinueDirection" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="revDir"/>
<xsd:enumeration value="sameDir"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_Breakpoint" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="endCnv"/>
<xsd:enumeration value="bal"/>
<xsd:enumeration value="fixed"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_Offset" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="ctr"/>
<xsd:enumeration value="off"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_HierarchyAlignment" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="tL"/>
<xsd:enumeration value="tR"/>
<xsd:enumeration value="tCtrCh"/>
<xsd:enumeration value="tCtrDes"/>
<xsd:enumeration value="bL"/>
<xsd:enumeration value="bR"/>
<xsd:enumeration value="bCtrCh"/>
<xsd:enumeration value="bCtrDes"/>
<xsd:enumeration value="lT"/>
<xsd:enumeration value="lB"/>
<xsd:enumeration value="lCtrCh"/>
<xsd:enumeration value="lCtrDes"/>
<xsd:enumeration value="rT"/>
<xsd:enumeration value="rB"/>
<xsd:enumeration value="rCtrCh"/>
<xsd:enumeration value="rCtrDes"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_FunctionValue" final="restriction">
<xsd:union
memberTypes="xsd:int xsd:boolean ST_Direction ST_HierBranchStyle ST_AnimOneStr ST_AnimLvlStr ST_ResizeHandlesStr"
/>
</xsd:simpleType>
<xsd:simpleType name="ST_VariableType" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="none"/>
<xsd:enumeration value="orgChart"/>
<xsd:enumeration value="chMax"/>
<xsd:enumeration value="chPref"/>
<xsd:enumeration value="bulEnabled"/>
<xsd:enumeration value="dir"/>
<xsd:enumeration value="hierBranch"/>
<xsd:enumeration value="animOne"/>
<xsd:enumeration value="animLvl"/>
<xsd:enumeration value="resizeHandles"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_FunctionArgument" final="restriction">
<xsd:union memberTypes="ST_VariableType"/>
</xsd:simpleType>
<xsd:simpleType name="ST_OutputShapeType" final="restriction">
<xsd:restriction base="xsd:token">
<xsd:enumeration value="none"/>
<xsd:enumeration value="conn"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.openxmlformats.org/drawingml/2006/lockedCanvas"
xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
elementFormDefault="qualified"
targetNamespace="http://schemas.openxmlformats.org/drawingml/2006/lockedCanvas">
<xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/main"
schemaLocation="dml-main.xsd"/>
<xsd:element name="lockedCanvas" type="a:CT_GvmlGroupShape"/>
</xsd:schema>
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.openxmlformats.org/drawingml/2006/picture"
xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" elementFormDefault="qualified"
targetNamespace="http://schemas.openxmlformats.org/drawingml/2006/picture">
<xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/main"
schemaLocation="dml-main.xsd"/>
<xsd:complexType name="CT_PictureNonVisual">
<xsd:sequence>
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
<xsd:element name="cNvPicPr" type="a:CT_NonVisualPictureProperties" minOccurs="1"
maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_Picture">
<xsd:sequence minOccurs="1" maxOccurs="1">
<xsd:element name="nvPicPr" type="CT_PictureNonVisual" minOccurs="1" maxOccurs="1"/>
<xsd:element name="blipFill" type="a:CT_BlipFillProperties" minOccurs="1" maxOccurs="1"/>
<xsd:element name="spPr" type="a:CT_ShapeProperties" minOccurs="1" maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="pic" type="CT_Picture"/>
</xsd:schema>
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.openxmlformats.org/officeDocument/2006/characteristics"
targetNamespace="http://schemas.openxmlformats.org/officeDocument/2006/characteristics"
elementFormDefault="qualified">
<xsd:complexType name="CT_AdditionalCharacteristics">
<xsd:sequence>
<xsd:element name="characteristic" type="CT_Characteristic" minOccurs="0"
maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_Characteristic">
<xsd:attribute name="name" type="xsd:string" use="required"/>
<xsd:attribute name="relation" type="ST_Relation" use="required"/>
<xsd:attribute name="val" type="xsd:string" use="required"/>
<xsd:attribute name="vocabulary" type="xsd:anyURI" use="optional"/>
</xsd:complexType>
<xsd:simpleType name="ST_Relation">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="ge"/>
<xsd:enumeration value="le"/>
<xsd:enumeration value="gt"/>
<xsd:enumeration value="lt"/>
<xsd:enumeration value="eq"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:element name="additionalCharacteristics" type="CT_AdditionalCharacteristics"/>
</xsd:schema>
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.openxmlformats.org/officeDocument/2006/customXml"
xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
targetNamespace="http://schemas.openxmlformats.org/officeDocument/2006/customXml"
elementFormDefault="qualified" attributeFormDefault="qualified" blockDefault="#all">
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
schemaLocation="shared-commonSimpleTypes.xsd"/>
<xsd:complexType name="CT_DatastoreSchemaRef">
<xsd:attribute name="uri" type="xsd:string" use="required"/>
</xsd:complexType>
<xsd:complexType name="CT_DatastoreSchemaRefs">
<xsd:sequence>
<xsd:element name="schemaRef" type="CT_DatastoreSchemaRef" minOccurs="0" maxOccurs="unbounded"
/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CT_DatastoreItem">
<xsd:sequence>
<xsd:element name="schemaRefs" type="CT_DatastoreSchemaRefs" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="itemID" type="s:ST_Guid" use="required"/>
</xsd:complexType>
<xsd:element name="datastoreItem" type="CT_DatastoreItem"/>
</xsd:schema>
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.openxmlformats.org/schemaLibrary/2006/main"
targetNamespace="http://schemas.openxmlformats.org/schemaLibrary/2006/main"
attributeFormDefault="qualified" elementFormDefault="qualified">
<xsd:complexType name="CT_Schema">
<xsd:attribute name="uri" type="xsd:string" default=""/>
<xsd:attribute name="manifestLocation" type="xsd:string"/>
<xsd:attribute name="schemaLocation" type="xsd:string"/>
<xsd:attribute name="schemaLanguage" type="xsd:token"/>
</xsd:complexType>
<xsd:complexType name="CT_SchemaLibrary">
<xsd:sequence>
<xsd:element name="schema" type="CT_Schema" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="schemaLibrary" type="CT_SchemaLibrary"/>
</xsd:schema>
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="urn:schemas-microsoft-com:office:powerpoint"
targetNamespace="urn:schemas-microsoft-com:office:powerpoint" elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xsd:element name="iscomment" type="CT_Empty"/>
<xsd:element name="textdata" type="CT_Rel"/>
<xsd:complexType name="CT_Empty"/>
<xsd:complexType name="CT_Rel">
<xsd:attribute name="id" type="xsd:string"/>
</xsd:complexType>
</xsd:schema>
"""
Validation modules for Word document processing.
"""
from .base import BaseSchemaValidator
from .docx import DOCXSchemaValidator
from .pptx import PPTXSchemaValidator
from .redlining import RedliningValidator
__all__ = [
"BaseSchemaValidator",
"DOCXSchemaValidator",
"PPTXSchemaValidator",
"RedliningValidator",
]
Related skills
FAQ
How does pptx analyze an existing template deck?
pptx runs python scripts/thumbnail.py on template.pptx to produce thumbnails.jpg for layout review, then python -m markitdown template.pptx to extract placeholder text. Developers map each content section to a matching template slide.
What layout variety does pptx recommend?
pptx recommends multi-column, image-plus-text, full-bleed image overlays, and quote callout layouts. The skill explicitly warns against defaulting to basic title-and-bullet slides for every section.
Is Pptx safe to install?
skills.sh reports 2 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.