mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-13 03:13:41 +08:00
fix(skills): 补齐技能自带 scripts(去AI化检测脚本等)到开源
This commit is contained in:
parent
973c4c508c
commit
f6fb7f2556
170
mateclaw-desktop/scripts/README.md
Normal file
170
mateclaw-desktop/scripts/README.md
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
# MateClaw Desktop - Build & Publish Scripts
|
||||||
|
|
||||||
|
## Scripts
|
||||||
|
|
||||||
|
| Script | Description |
|
||||||
|
|--------|-------------|
|
||||||
|
| `build.sh` | Build backend JAR (frontend + Spring Boot) |
|
||||||
|
| `download-jre.sh` | Download Adoptium JRE 21 for target platform |
|
||||||
|
| `build-all-platforms.sh` | One-click build for all platforms (macOS + Windows) |
|
||||||
|
| `publish-github.sh` | Publish release artifacts to GitHub Releases |
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### Full Build + Publish (recommended)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd mateclaw-desktop
|
||||||
|
|
||||||
|
# Step 1: Build for all platforms (no publish)
|
||||||
|
bash scripts/build-all-platforms.sh --all
|
||||||
|
|
||||||
|
# Step 2: Publish to GitHub (via proxy)
|
||||||
|
bash scripts/publish-github.sh --proxy
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step-by-Step Build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd mateclaw-desktop
|
||||||
|
|
||||||
|
# 1. Build backend JAR (frontend + Spring Boot)
|
||||||
|
bash scripts/build.sh
|
||||||
|
|
||||||
|
# 2. Download JRE for target platform
|
||||||
|
bash scripts/download-jre.sh mac-arm64 # Apple Silicon
|
||||||
|
bash scripts/download-jre.sh mac-x64 # Intel Mac
|
||||||
|
bash scripts/download-jre.sh win-x64 # Windows x64
|
||||||
|
bash scripts/download-jre.sh win-arm64 # Windows ARM
|
||||||
|
|
||||||
|
# 3. Build frontend and package
|
||||||
|
npm run build
|
||||||
|
npx electron-builder --mac # macOS
|
||||||
|
npx electron-builder --win --x64 # Windows x64
|
||||||
|
npx electron-builder --win --arm64 # Windows ARM
|
||||||
|
```
|
||||||
|
|
||||||
|
## build.sh
|
||||||
|
|
||||||
|
Build the backend JAR, includes three steps:
|
||||||
|
|
||||||
|
1. Build Vue 3 frontend to `mateclaw-server/src/main/resources/static`
|
||||||
|
2. Package Spring Boot fat JAR via Maven
|
||||||
|
3. Copy JAR to `mateclaw-desktop/resources/app.jar`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash scripts/build.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
**Prerequisites:** Node.js (pnpm or npm), Maven (or mvnw)
|
||||||
|
|
||||||
|
## download-jre.sh
|
||||||
|
|
||||||
|
Download Adoptium JRE 21 for the target platform.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Auto-detect current platform
|
||||||
|
bash scripts/download-jre.sh
|
||||||
|
|
||||||
|
# Specify platform
|
||||||
|
bash scripts/download-jre.sh mac-arm64
|
||||||
|
bash scripts/download-jre.sh mac-x64
|
||||||
|
bash scripts/download-jre.sh win-x64
|
||||||
|
bash scripts/download-jre.sh win-arm64
|
||||||
|
```
|
||||||
|
|
||||||
|
JRE will be saved to `resources/jre/{os}-{arch}/`.
|
||||||
|
|
||||||
|
## build-all-platforms.sh
|
||||||
|
|
||||||
|
Orchestrates the full build pipeline: JAR build -> JRE download -> frontend compile -> electron-builder package.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash scripts/build-all-platforms.sh --all # macOS + Windows
|
||||||
|
bash scripts/build-all-platforms.sh --mac-only # macOS only
|
||||||
|
bash scripts/build-all-platforms.sh --win-only # Windows only
|
||||||
|
```
|
||||||
|
|
||||||
|
Build artifacts are output to `release/` directory.
|
||||||
|
|
||||||
|
## publish-github.sh
|
||||||
|
|
||||||
|
Publish build artifacts from `release/` to GitHub Releases via `gh` CLI.
|
||||||
|
|
||||||
|
### Basic Usage
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash scripts/publish-github.sh # Direct upload
|
||||||
|
bash scripts/publish-github.sh --draft # Create draft release
|
||||||
|
bash scripts/publish-github.sh --tag=v1.1.0 # Custom tag
|
||||||
|
```
|
||||||
|
|
||||||
|
### With Proxy (for slow or restricted networks)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash scripts/publish-github.sh --proxy # Default proxy: 127.0.0.1:7890
|
||||||
|
bash scripts/publish-github.sh --proxy=192.168.1.1:8080 # Custom proxy
|
||||||
|
bash scripts/publish-github.sh --proxy --draft # Draft + proxy
|
||||||
|
```
|
||||||
|
|
||||||
|
### Retry Failed Upload
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash scripts/publish-github.sh --proxy --retry # Delete old release, re-upload
|
||||||
|
bash scripts/publish-github.sh --proxy --retry --draft # Retry as draft
|
||||||
|
```
|
||||||
|
|
||||||
|
### All Options
|
||||||
|
|
||||||
|
| Option | Description |
|
||||||
|
|--------|-------------|
|
||||||
|
| `--proxy` | Use proxy `127.0.0.1:7890` for GitHub upload |
|
||||||
|
| `--proxy=host:port` | Use custom proxy address |
|
||||||
|
| `--draft` | Create as draft release |
|
||||||
|
| `--tag=vX.Y.Z` | Custom tag (default: `v{version}` from package.json) |
|
||||||
|
| `--retry` | Delete existing release for this tag before re-uploading |
|
||||||
|
|
||||||
|
**Prerequisites:** [gh CLI](https://cli.github.com/) installed and authenticated (`gh auth login`)
|
||||||
|
|
||||||
|
## npm Scripts
|
||||||
|
|
||||||
|
These scripts are also available as npm commands:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run setup:jar # build.sh
|
||||||
|
npm run setup:jre # download-jre.sh
|
||||||
|
npm run setup # build.sh + download-jre.sh
|
||||||
|
npm run package:mac # Build frontend + electron-builder --mac
|
||||||
|
npm run package:win # Build frontend + electron-builder --win
|
||||||
|
npm run package:all # build-all-platforms.sh --all
|
||||||
|
npm run publish:github # publish-github.sh
|
||||||
|
npm run publish:github:draft # publish-github.sh --draft
|
||||||
|
```
|
||||||
|
|
||||||
|
## Typical Workflow
|
||||||
|
|
||||||
|
```
|
||||||
|
build.sh download-jre.sh
|
||||||
|
| |
|
||||||
|
v v
|
||||||
|
resources/app.jar resources/jre/{os}-{arch}/
|
||||||
|
| |
|
||||||
|
+--------- electron-builder ---+
|
||||||
|
|
|
||||||
|
v
|
||||||
|
release/
|
||||||
|
├── MateClaw_1.0.0_arm64.dmg
|
||||||
|
├── MateClaw_1.0.0_x64.dmg
|
||||||
|
├── MateClaw_1.0.0_arm64.zip
|
||||||
|
├── MateClaw_1.0.0_x64.zip
|
||||||
|
├── MateClaw_1.0.0_arm64_Setup.exe
|
||||||
|
├── MateClaw_1.0.0_x64_Setup.exe
|
||||||
|
├── latest-mac.yml
|
||||||
|
└── latest.yml
|
||||||
|
|
|
||||||
|
v
|
||||||
|
publish-github.sh
|
||||||
|
|
|
||||||
|
v
|
||||||
|
GitHub Releases
|
||||||
|
```
|
||||||
@ -0,0 +1,151 @@
|
|||||||
|
const assert = require('node:assert/strict')
|
||||||
|
const fs = require('node:fs')
|
||||||
|
const os = require('node:os')
|
||||||
|
const path = require('node:path')
|
||||||
|
const test = require('node:test')
|
||||||
|
|
||||||
|
const {
|
||||||
|
createZipBuffer,
|
||||||
|
readZipEntries,
|
||||||
|
resolveDriverDirectory,
|
||||||
|
trimDriverBundleInAppJar,
|
||||||
|
ZIP_STORED,
|
||||||
|
default: afterPack,
|
||||||
|
} = require('../trim-playwright-driver.cjs')
|
||||||
|
|
||||||
|
test('resolveDriverDirectory maps electron platform and arch to Playwright driver folder', () => {
|
||||||
|
assert.equal(resolveDriverDirectory('darwin', 'x64'), 'driver/mac')
|
||||||
|
assert.equal(resolveDriverDirectory('darwin', 'arm64'), 'driver/mac-arm64')
|
||||||
|
assert.equal(resolveDriverDirectory('linux', 'x64'), 'driver/linux')
|
||||||
|
assert.equal(resolveDriverDirectory('linux', 'arm64'), 'driver/linux-arm64')
|
||||||
|
assert.equal(resolveDriverDirectory('win32', 'x64'), 'driver/win32_x64')
|
||||||
|
assert.equal(resolveDriverDirectory('win32', 'arm64'), 'driver/win32_x64')
|
||||||
|
assert.deepEqual(resolveDriverDirectory('darwin', 'universal'), ['driver/mac', 'driver/mac-arm64'])
|
||||||
|
})
|
||||||
|
|
||||||
|
test('trimDriverBundleInAppJar keeps only the target driver and preserves nested jar as STORED', async () => {
|
||||||
|
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'mateclaw-driver-trim-'))
|
||||||
|
const appJarPath = path.join(tmp, 'app.jar')
|
||||||
|
|
||||||
|
const driverBundle = createZipBuffer([
|
||||||
|
entry('META-INF/MANIFEST.MF', 'Manifest-Version: 1.0\n'),
|
||||||
|
entry('driver/mac/node', 'mac'),
|
||||||
|
entry('driver/mac-arm64/node', 'mac-arm64'),
|
||||||
|
entry('driver/linux/node', 'linux'),
|
||||||
|
entry('driver/linux-arm64/node', 'linux-arm64'),
|
||||||
|
entry('driver/win32_x64/node.exe', 'win32'),
|
||||||
|
entry('com/microsoft/playwright/Driver.class', 'class'),
|
||||||
|
])
|
||||||
|
|
||||||
|
const appJar = createZipBuffer([
|
||||||
|
entry('BOOT-INF/classpath.idx', '- "BOOT-INF/lib/driver-bundle-1.52.0.jar"\n'),
|
||||||
|
entry('BOOT-INF/lib/driver-bundle-1.52.0.jar', driverBundle, ZIP_STORED),
|
||||||
|
entry('BOOT-INF/lib/other.jar', 'other', ZIP_STORED),
|
||||||
|
])
|
||||||
|
|
||||||
|
fs.writeFileSync(appJarPath, appJar)
|
||||||
|
|
||||||
|
const result = await trimDriverBundleInAppJar(appJarPath, 'driver/mac-arm64')
|
||||||
|
assert.equal(result.removedDriverEntries, 4)
|
||||||
|
|
||||||
|
const outerEntries = readZipEntries(fs.readFileSync(appJarPath))
|
||||||
|
const nestedEntry = outerEntries.find((item) => item.name === 'BOOT-INF/lib/driver-bundle-1.52.0.jar')
|
||||||
|
assert.equal(nestedEntry.method, ZIP_STORED)
|
||||||
|
|
||||||
|
const innerEntries = readZipEntries(nestedEntry.data)
|
||||||
|
const names = innerEntries.map((item) => item.name).sort()
|
||||||
|
|
||||||
|
assert.deepEqual(names, [
|
||||||
|
'META-INF/MANIFEST.MF',
|
||||||
|
'com/microsoft/playwright/Driver.class',
|
||||||
|
'driver/mac-arm64/node',
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
test('trimDriverBundleInAppJar throws when driver-bundle is missing', async () => {
|
||||||
|
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'mateclaw-driver-trim-'))
|
||||||
|
const appJarPath = path.join(tmp, 'app.jar')
|
||||||
|
|
||||||
|
fs.writeFileSync(appJarPath, createZipBuffer([
|
||||||
|
entry('BOOT-INF/lib/other.jar', 'other', ZIP_STORED),
|
||||||
|
]))
|
||||||
|
|
||||||
|
await assert.rejects(
|
||||||
|
() => trimDriverBundleInAppJar(appJarPath, 'driver/mac-arm64'),
|
||||||
|
/Playwright driver-bundle jar not found/
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('trimDriverBundleInAppJar throws when no target driver entries are kept', async () => {
|
||||||
|
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'mateclaw-driver-trim-'))
|
||||||
|
const appJarPath = path.join(tmp, 'app.jar')
|
||||||
|
fs.writeFileSync(appJarPath, createAppJarWithDriverBundle())
|
||||||
|
|
||||||
|
await assert.rejects(
|
||||||
|
() => trimDriverBundleInAppJar(appJarPath, 'driver/mac-arm64-v2'),
|
||||||
|
/No entries kept under driver\/mac-arm64-v2/
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('trimDriverBundleInAppJar can keep both mac drivers for universal builds', async () => {
|
||||||
|
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'mateclaw-driver-trim-'))
|
||||||
|
const appJarPath = path.join(tmp, 'app.jar')
|
||||||
|
fs.writeFileSync(appJarPath, createAppJarWithDriverBundle())
|
||||||
|
|
||||||
|
const result = await trimDriverBundleInAppJar(appJarPath, ['driver/mac', 'driver/mac-arm64'])
|
||||||
|
assert.equal(result.keptDriverEntries, 2)
|
||||||
|
|
||||||
|
const outerEntries = readZipEntries(fs.readFileSync(appJarPath))
|
||||||
|
const nestedEntry = outerEntries.find((item) => item.name === 'BOOT-INF/lib/driver-bundle-1.52.0.jar')
|
||||||
|
const driverNames = readZipEntries(nestedEntry.data)
|
||||||
|
.filter((item) => item.name.startsWith('driver/'))
|
||||||
|
.map((item) => item.name)
|
||||||
|
.sort()
|
||||||
|
|
||||||
|
assert.deepEqual(driverNames, [
|
||||||
|
'driver/mac-arm64/node',
|
||||||
|
'driver/mac/node',
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
test('afterPack throws when app.jar is missing', async () => {
|
||||||
|
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'mateclaw-driver-trim-'))
|
||||||
|
|
||||||
|
await assert.rejects(
|
||||||
|
() => afterPack({
|
||||||
|
appOutDir: tmp,
|
||||||
|
arch: 'arm64',
|
||||||
|
electronPlatformName: 'darwin',
|
||||||
|
packager: {
|
||||||
|
appInfo: { productFilename: 'MateClaw' },
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
/app\.jar not found/
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
function entry(name, data, method) {
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
data: Buffer.isBuffer(data) ? data : Buffer.from(data),
|
||||||
|
method,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createAppJarWithDriverBundle() {
|
||||||
|
const driverBundle = createZipBuffer([
|
||||||
|
entry('META-INF/MANIFEST.MF', 'Manifest-Version: 1.0\n'),
|
||||||
|
entry('driver/mac/node', 'mac'),
|
||||||
|
entry('driver/mac-arm64/node', 'mac-arm64'),
|
||||||
|
entry('driver/linux/node', 'linux'),
|
||||||
|
entry('driver/linux-arm64/node', 'linux-arm64'),
|
||||||
|
entry('driver/win32_x64/node.exe', 'win32'),
|
||||||
|
entry('com/microsoft/playwright/Driver.class', 'class'),
|
||||||
|
])
|
||||||
|
|
||||||
|
return createZipBuffer([
|
||||||
|
entry('BOOT-INF/classpath.idx', '- "BOOT-INF/lib/driver-bundle-1.52.0.jar"\n'),
|
||||||
|
entry('BOOT-INF/lib/driver-bundle-1.52.0.jar', driverBundle, ZIP_STORED),
|
||||||
|
entry('BOOT-INF/lib/other.jar', 'other', ZIP_STORED),
|
||||||
|
])
|
||||||
|
}
|
||||||
324
mateclaw-desktop/scripts/publish-github.sh
Executable file
324
mateclaw-desktop/scripts/publish-github.sh
Executable file
@ -0,0 +1,324 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Publish MateClaw Desktop release artifacts to GitHub Releases
|
||||||
|
#
|
||||||
|
# Prerequisites:
|
||||||
|
# - gh CLI installed and authenticated (gh auth login)
|
||||||
|
# - Build artifacts exist in release/ directory (run build-all-platforms.sh first)
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# bash scripts/publish-github.sh # Create release (direct)
|
||||||
|
# bash scripts/publish-github.sh --proxy # Create release via proxy (127.0.0.1:7890)
|
||||||
|
# bash scripts/publish-github.sh --proxy=host:port # Create release via custom proxy
|
||||||
|
# bash scripts/publish-github.sh --draft # Create draft release
|
||||||
|
# bash scripts/publish-github.sh --tag=v1.1.0 # Custom tag (default: v{version} from package.json)
|
||||||
|
# bash scripts/publish-github.sh --retry # Delete existing release and re-upload
|
||||||
|
# bash scripts/publish-github.sh --proxy --retry --draft # Combine options
|
||||||
|
#
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
DESKTOP_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||||
|
RELEASE_DIR="$DESKTOP_DIR/release"
|
||||||
|
|
||||||
|
# ─── Parse arguments ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
DRAFT=""
|
||||||
|
CUSTOM_TAG=""
|
||||||
|
USE_PROXY=""
|
||||||
|
PROXY_ADDR="127.0.0.1:7890"
|
||||||
|
RETRY=false
|
||||||
|
NOTES_FILE_OVERRIDE=""
|
||||||
|
NOTES_LANG="en"
|
||||||
|
|
||||||
|
for arg in "$@"; do
|
||||||
|
case "$arg" in
|
||||||
|
--draft) DRAFT="--draft" ;;
|
||||||
|
--tag=*) CUSTOM_TAG="${arg#--tag=}" ;;
|
||||||
|
--proxy) USE_PROXY=true ;;
|
||||||
|
--proxy=*) USE_PROXY=true; PROXY_ADDR="${arg#--proxy=}" ;;
|
||||||
|
--retry) RETRY=true ;;
|
||||||
|
--notes-file=*) NOTES_FILE_OVERRIDE="${arg#--notes-file=}" ;;
|
||||||
|
--notes-lang=*) NOTES_LANG="${arg#--notes-lang=}" ;;
|
||||||
|
-h|--help)
|
||||||
|
echo "Usage: $0 [--draft] [--tag=vX.Y.Z] [--proxy[=host:port]] [--retry] [--notes-file=path] [--notes-lang=en|zh]"
|
||||||
|
echo ""
|
||||||
|
echo "Options:"
|
||||||
|
echo " --draft Create as draft release"
|
||||||
|
echo " --tag=vX.Y.Z Custom tag (default: v{version} from package.json)"
|
||||||
|
echo " --proxy Use proxy 127.0.0.1:7890 for uploading to GitHub"
|
||||||
|
echo " --proxy=host:port Use custom proxy address"
|
||||||
|
echo " --retry Delete existing release for this tag before uploading"
|
||||||
|
echo " --notes-file=path Use this markdown file as release notes (highest priority)"
|
||||||
|
echo " --notes-lang=en|zh Preferred language for auto-detected notes (default: en)"
|
||||||
|
echo ""
|
||||||
|
echo "Release notes resolution order:"
|
||||||
|
echo " 1. --notes-file=path (explicit override)"
|
||||||
|
echo " 2. ../docs/{notes-lang}/releases/X.Y.Z.md (curated, preferred lang)"
|
||||||
|
echo " 3. ../docs/{other-lang}/releases/X.Y.Z.md (curated, fallback lang)"
|
||||||
|
echo " 4. Tag annotation (if multi-line) (legacy)"
|
||||||
|
echo " 5. Tagged commit message body (legacy)"
|
||||||
|
echo " 6. --generate-notes (GitHub auto)"
|
||||||
|
echo ""
|
||||||
|
echo "Examples:"
|
||||||
|
echo " # Step 1: Build locally (no publish)"
|
||||||
|
echo " bash scripts/build-all-platforms.sh --all"
|
||||||
|
echo ""
|
||||||
|
echo " # Step 2: Publish to GitHub"
|
||||||
|
echo " bash scripts/publish-github.sh --proxy # via proxy, en notes"
|
||||||
|
echo " bash scripts/publish-github.sh --proxy --notes-lang=zh # zh notes"
|
||||||
|
echo " bash scripts/publish-github.sh --proxy --draft # draft (preview)"
|
||||||
|
echo " bash scripts/publish-github.sh --proxy --retry # delete + re-upload"
|
||||||
|
echo " bash scripts/publish-github.sh --notes-file=NOTES.md # custom notes file"
|
||||||
|
echo ""
|
||||||
|
echo "Run build-all-platforms.sh first to generate artifacts."
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown option: $arg"
|
||||||
|
echo "Usage: $0 [--draft] [--tag=vX.Y.Z] [--proxy[=host:port]] [--retry] [--notes-file=path] [--notes-lang=en|zh]"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$NOTES_LANG" != "en" ] && [ "$NOTES_LANG" != "zh" ]; then
|
||||||
|
echo "❌ --notes-lang must be 'en' or 'zh' (got: $NOTES_LANG)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ─── Setup proxy ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
if [ "$USE_PROXY" = true ]; then
|
||||||
|
export https_proxy="http://${PROXY_ADDR}"
|
||||||
|
export http_proxy="http://${PROXY_ADDR}"
|
||||||
|
export HTTPS_PROXY="http://${PROXY_ADDR}"
|
||||||
|
export HTTP_PROXY="http://${PROXY_ADDR}"
|
||||||
|
echo "🌐 Proxy enabled: ${PROXY_ADDR}"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ─── Check prerequisites ──────────────────────────────────────────────────
|
||||||
|
|
||||||
|
if ! command -v gh &>/dev/null; then
|
||||||
|
echo "❌ gh CLI not found. Install: https://cli.github.com/"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! gh auth status &>/dev/null; then
|
||||||
|
echo "❌ gh not authenticated. Run: gh auth login"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ─── Read version from package.json ───────────────────────────────────────
|
||||||
|
|
||||||
|
VERSION=$(node -p "require('$DESKTOP_DIR/package.json').version")
|
||||||
|
TAG="${CUSTOM_TAG:-v${VERSION}}"
|
||||||
|
|
||||||
|
echo "╔════════════════════════════════════════════════════════╗"
|
||||||
|
echo "║ MateClaw Desktop - Publish to GitHub ║"
|
||||||
|
echo "╚════════════════════════════════════════════════════════╝"
|
||||||
|
echo ""
|
||||||
|
echo " Version: $VERSION"
|
||||||
|
echo " Tag: $TAG"
|
||||||
|
echo " Mode: ${DRAFT:-release}"
|
||||||
|
echo " Proxy: ${USE_PROXY:+${PROXY_ADDR}}${USE_PROXY:-off}"
|
||||||
|
echo " Retry: $RETRY"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# ─── Retry: delete existing release ───────────────────────────────────────
|
||||||
|
|
||||||
|
if [ "$RETRY" = true ]; then
|
||||||
|
echo "🔄 Checking for existing release $TAG ..."
|
||||||
|
if gh release view "$TAG" &>/dev/null; then
|
||||||
|
echo " Found existing release, deleting..."
|
||||||
|
gh release delete "$TAG" --yes --cleanup-tag 2>/dev/null || gh release delete "$TAG" --yes 2>/dev/null
|
||||||
|
echo " ✅ Old release deleted."
|
||||||
|
else
|
||||||
|
echo " No existing release found, proceeding."
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ─── Collect release artifacts ─────────────────────────────────────────────
|
||||||
|
|
||||||
|
if [ ! -d "$RELEASE_DIR" ]; then
|
||||||
|
echo "❌ Release directory not found: $RELEASE_DIR"
|
||||||
|
echo " Run build-all-platforms.sh first."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
ARTIFACTS=()
|
||||||
|
|
||||||
|
# macOS artifacts
|
||||||
|
for pattern in "MateClaw*.dmg" "MateClaw*.zip"; do
|
||||||
|
while IFS= read -r -d '' f; do
|
||||||
|
ARTIFACTS+=("$f")
|
||||||
|
done < <(find "$RELEASE_DIR" -maxdepth 1 -name "$pattern" -print0 2>/dev/null)
|
||||||
|
done
|
||||||
|
|
||||||
|
# Windows artifacts (skip the architecture-merged installer — only ship per-arch builds)
|
||||||
|
while IFS= read -r -d '' f; do
|
||||||
|
ARTIFACTS+=("$f")
|
||||||
|
done < <(find "$RELEASE_DIR" -maxdepth 1 -name "MateClaw*Setup*.exe" \
|
||||||
|
! -name "MateClaw_${VERSION}_Setup.exe" -print0 2>/dev/null)
|
||||||
|
|
||||||
|
# Linux artifacts
|
||||||
|
while IFS= read -r -d '' f; do
|
||||||
|
ARTIFACTS+=("$f")
|
||||||
|
done < <(find "$RELEASE_DIR" -maxdepth 1 -name "MateClaw*.AppImage" -print0 2>/dev/null)
|
||||||
|
|
||||||
|
# Auto-update metadata files
|
||||||
|
for pattern in "latest-mac.yml" "latest.yml" "latest-linux.yml"; do
|
||||||
|
if [ -f "$RELEASE_DIR/$pattern" ]; then
|
||||||
|
ARTIFACTS+=("$RELEASE_DIR/$pattern")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# blockmap files (for differential updates) — also skip merged installer's blockmap
|
||||||
|
while IFS= read -r -d '' f; do
|
||||||
|
ARTIFACTS+=("$f")
|
||||||
|
done < <(find "$RELEASE_DIR" -maxdepth 1 -name "*.blockmap" \
|
||||||
|
! -name "MateClaw_${VERSION}_Setup.exe.blockmap" -print0 2>/dev/null)
|
||||||
|
|
||||||
|
if [ ${#ARTIFACTS[@]} -eq 0 ]; then
|
||||||
|
echo "❌ No release artifacts found in $RELEASE_DIR"
|
||||||
|
echo " Run build-all-platforms.sh first."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo " Artifacts to upload:"
|
||||||
|
TOTAL_SIZE=0
|
||||||
|
for f in "${ARTIFACTS[@]}"; do
|
||||||
|
SIZE_BYTES=$(stat -f%z "$f" 2>/dev/null || stat -c%s "$f" 2>/dev/null || echo 0)
|
||||||
|
SIZE_HUMAN=$(du -h "$f" | cut -f1)
|
||||||
|
TOTAL_SIZE=$((TOTAL_SIZE + SIZE_BYTES))
|
||||||
|
echo " • $(basename "$f") ($SIZE_HUMAN)"
|
||||||
|
done
|
||||||
|
TOTAL_HUMAN=$(echo "$TOTAL_SIZE" | awk '{
|
||||||
|
if ($1 >= 1073741824) printf "%.1f GB", $1/1073741824;
|
||||||
|
else if ($1 >= 1048576) printf "%.0f MB", $1/1048576;
|
||||||
|
else printf "%.0f KB", $1/1024;
|
||||||
|
}')
|
||||||
|
echo ""
|
||||||
|
echo " Total: $TOTAL_HUMAN"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# ─── Resolve release notes (priority chain) ───────────────────────────────
|
||||||
|
# 1. --notes-file=path (explicit override)
|
||||||
|
# 2. ../docs/{notes-lang}/releases/X.Y.Z.md (curated, preferred lang)
|
||||||
|
# 3. ../docs/{other-lang}/releases/X.Y.Z.md (curated, fallback lang)
|
||||||
|
# 4. Tag annotation (if multi-line) (legacy fallback)
|
||||||
|
# 5. Tagged commit message body (legacy fallback)
|
||||||
|
# 6. --generate-notes (GitHub auto)
|
||||||
|
|
||||||
|
NOTES_FILE=$(mktemp)
|
||||||
|
trap "rm -f '$NOTES_FILE'" EXIT
|
||||||
|
|
||||||
|
REPO_ROOT="$(cd "$DESKTOP_DIR/.." && pwd)"
|
||||||
|
NOTES_LANG_OTHER=$([ "$NOTES_LANG" = "en" ] && echo "zh" || echo "en")
|
||||||
|
NOTES_PRIMARY="$REPO_ROOT/docs/${NOTES_LANG}/releases/${VERSION}.md"
|
||||||
|
NOTES_FALLBACK="$REPO_ROOT/docs/${NOTES_LANG_OTHER}/releases/${VERSION}.md"
|
||||||
|
|
||||||
|
if [ -n "$NOTES_FILE_OVERRIDE" ]; then
|
||||||
|
if [ ! -f "$NOTES_FILE_OVERRIDE" ]; then
|
||||||
|
echo "❌ --notes-file path not found: $NOTES_FILE_OVERRIDE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
cat "$NOTES_FILE_OVERRIDE" > "$NOTES_FILE"
|
||||||
|
echo "📝 Using --notes-file: $NOTES_FILE_OVERRIDE"
|
||||||
|
elif [ -f "$NOTES_PRIMARY" ]; then
|
||||||
|
cat "$NOTES_PRIMARY" > "$NOTES_FILE"
|
||||||
|
echo "📝 Using docs/${NOTES_LANG}/releases/${VERSION}.md as release notes."
|
||||||
|
elif [ -f "$NOTES_FALLBACK" ]; then
|
||||||
|
cat "$NOTES_FALLBACK" > "$NOTES_FILE"
|
||||||
|
echo "📝 Using docs/${NOTES_LANG_OTHER}/releases/${VERSION}.md as release notes (preferred '$NOTES_LANG' not found)."
|
||||||
|
else
|
||||||
|
# Legacy fallback: tag annotation, then commit body
|
||||||
|
TAG_MSG=$(git tag -l --format='%(contents)' "$TAG" 2>/dev/null | sed '/^$/d')
|
||||||
|
if [ -n "$TAG_MSG" ] && [ "$(echo "$TAG_MSG" | wc -l)" -gt 2 ]; then
|
||||||
|
echo "$TAG_MSG" > "$NOTES_FILE"
|
||||||
|
echo "📝 Using tag annotation as release notes."
|
||||||
|
else
|
||||||
|
COMMIT_MSG=$(git log -1 --format='%B' "$TAG" 2>/dev/null | tail -n +2 | sed '/^$/d')
|
||||||
|
if [ -n "$COMMIT_MSG" ]; then
|
||||||
|
echo "$COMMIT_MSG" > "$NOTES_FILE"
|
||||||
|
echo "📝 Using commit message as release notes."
|
||||||
|
else
|
||||||
|
echo "⚠️ No release notes found (no docs/X.Y.Z.md, tag annotation, or commit body), using --generate-notes."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# ─── Rewrite latest.yml so it does not reference the merged installer ─────
|
||||||
|
#
|
||||||
|
# electron-builder generates a multi-arch merged Windows installer
|
||||||
|
# (MateClaw_X.Y.Z_Setup.exe, ~600 MB) alongside the per-arch installers
|
||||||
|
# (MateClaw_X.Y.Z_x64_Setup.exe, MateClaw_X.Y.Z_arm64_Setup.exe). The
|
||||||
|
# merged build is too large to be worth uploading, but the default
|
||||||
|
# latest.yml top-level `path:` and `files[0]` both point at it. If we
|
||||||
|
# upload latest.yml as-is while skipping the merged exe, electron-updater
|
||||||
|
# on Windows hits 404 on every check and the whole update path breaks.
|
||||||
|
#
|
||||||
|
# Fix: rewrite latest.yml in place so `path` / `sha512` / `files[]` only
|
||||||
|
# reference assets that are actually being uploaded. Use x64 as the
|
||||||
|
# default top-level target (arm64 clients still match via files[]).
|
||||||
|
|
||||||
|
LATEST_YML="$RELEASE_DIR/latest.yml"
|
||||||
|
MERGED_EXE_NAME="MateClaw_${VERSION}_Setup.exe"
|
||||||
|
X64_EXE_NAME="MateClaw_${VERSION}_x64_Setup.exe"
|
||||||
|
ARM64_EXE_NAME="MateClaw_${VERSION}_arm64_Setup.exe"
|
||||||
|
|
||||||
|
if [ -f "$LATEST_YML" ]; then
|
||||||
|
echo "🧹 Rewriting latest.yml to drop the merged installer ..."
|
||||||
|
(cd "$DESKTOP_DIR" && node -e "
|
||||||
|
const fs = require('fs');
|
||||||
|
const yaml = require('js-yaml');
|
||||||
|
const file = '$LATEST_YML';
|
||||||
|
const merged = '$MERGED_EXE_NAME';
|
||||||
|
const x64 = '$X64_EXE_NAME';
|
||||||
|
const arm64 = '$ARM64_EXE_NAME';
|
||||||
|
const doc = yaml.load(fs.readFileSync(file, 'utf8'));
|
||||||
|
const before = (doc.files || []).length;
|
||||||
|
doc.files = (doc.files || []).filter(f => f.url !== merged);
|
||||||
|
const x64Entry = doc.files.find(f => f.url === x64);
|
||||||
|
const arm64Entry = doc.files.find(f => f.url === arm64);
|
||||||
|
if (!x64Entry || !arm64Entry) {
|
||||||
|
console.error('FATAL: per-arch installer entries missing from latest.yml');
|
||||||
|
console.error(' files:', doc.files.map(f => f.url));
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
doc.path = x64Entry.url;
|
||||||
|
doc.sha512 = x64Entry.sha512;
|
||||||
|
fs.writeFileSync(file, yaml.dump(doc, { lineWidth: -1 }));
|
||||||
|
console.log(' files[] entries: ' + before + ' → ' + doc.files.length);
|
||||||
|
console.log(' top-level path: ' + doc.path);
|
||||||
|
")
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ─── Create GitHub Release ─────────────────────────────────────────────────
|
||||||
|
|
||||||
|
echo "🚀 Creating GitHub Release $TAG ..."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
if [ -s "$NOTES_FILE" ]; then
|
||||||
|
gh release create "$TAG" \
|
||||||
|
--title "MateClaw $VERSION" \
|
||||||
|
--notes-file "$NOTES_FILE" \
|
||||||
|
$DRAFT \
|
||||||
|
"${ARTIFACTS[@]}"
|
||||||
|
else
|
||||||
|
gh release create "$TAG" \
|
||||||
|
--title "MateClaw $VERSION" \
|
||||||
|
--generate-notes \
|
||||||
|
$DRAFT \
|
||||||
|
"${ARTIFACTS[@]}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✅ Release published successfully!"
|
||||||
|
echo ""
|
||||||
|
gh release view "$TAG" --json url -q '.url'
|
||||||
@ -1,6 +1,360 @@
|
|||||||
// afterPack hook: no-op placeholder
|
const fs = require('node:fs')
|
||||||
// The original trim-playwright-driver.cjs was not included in the open-source release.
|
const path = require('node:path')
|
||||||
// This no-op allows electron-builder to complete packaging.
|
const zlib = require('node:zlib')
|
||||||
exports.default = async function () {
|
|
||||||
// intentionally empty
|
const ZIP_STORED = 0
|
||||||
|
const ZIP_DEFLATED = 8
|
||||||
|
const DRIVER_BUNDLE_PATTERN = /^BOOT-INF\/lib\/driver-bundle-[^/]+\.jar$/
|
||||||
|
|
||||||
|
const ARCH_X64 = 1
|
||||||
|
const ARCH_ARM64 = 3
|
||||||
|
|
||||||
|
async function afterPack(context) {
|
||||||
|
const platform = context.electronPlatformName || context.packager?.platform?.name
|
||||||
|
const arch = normalizeArch(context.arch)
|
||||||
|
const keepDriverDirectory = resolveDriverDirectory(platform, arch)
|
||||||
|
const appJarPath = findAppJar(context)
|
||||||
|
|
||||||
|
if (!appJarPath) {
|
||||||
|
throw new Error(`[trim-playwright-driver] app.jar not found in ${context.appOutDir}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await trimDriverBundleInAppJar(appJarPath, keepDriverDirectory)
|
||||||
|
const keptLabel = asArray(keepDriverDirectory).join(', ')
|
||||||
|
console.log(
|
||||||
|
`[trim-playwright-driver] ${path.relative(process.cwd(), appJarPath)}: ` +
|
||||||
|
`kept ${keptLabel}, removed ${result.removedDriverEntries} driver entries, ` +
|
||||||
|
`${formatBytes(result.beforeBytes)} -> ${formatBytes(result.afterBytes)}`
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function findAppJar(context) {
|
||||||
|
const appOutDir = context.appOutDir
|
||||||
|
const productFilename = context.packager?.appInfo?.productFilename || context.packager?.appInfo?.productName || 'MateClaw'
|
||||||
|
const platform = context.electronPlatformName || context.packager?.platform?.name
|
||||||
|
|
||||||
|
const candidates = []
|
||||||
|
if (platform === 'darwin') {
|
||||||
|
candidates.push(path.join(appOutDir, `${productFilename}.app`, 'Contents', 'Resources', 'app.jar'))
|
||||||
|
}
|
||||||
|
candidates.push(path.join(appOutDir, 'resources', 'app.jar'))
|
||||||
|
|
||||||
|
for (const candidate of candidates) {
|
||||||
|
if (fs.existsSync(candidate)) return candidate
|
||||||
|
}
|
||||||
|
|
||||||
|
const found = findFirstFile(appOutDir, 'app.jar', 4)
|
||||||
|
return found
|
||||||
|
}
|
||||||
|
|
||||||
|
function findFirstFile(root, fileName, maxDepth, depth = 0) {
|
||||||
|
if (!root || depth > maxDepth || !fs.existsSync(root)) return null
|
||||||
|
for (const dirent of fs.readdirSync(root, { withFileTypes: true })) {
|
||||||
|
const fullPath = path.join(root, dirent.name)
|
||||||
|
if (dirent.isFile() && dirent.name === fileName) return fullPath
|
||||||
|
if (dirent.isDirectory()) {
|
||||||
|
const found = findFirstFile(fullPath, fileName, maxDepth, depth + 1)
|
||||||
|
if (found) return found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
async function trimDriverBundleInAppJar(appJarPath, keepDriverDirectory) {
|
||||||
|
const appJarBuffer = fs.readFileSync(appJarPath)
|
||||||
|
const outerEntries = readZipEntries(appJarBuffer)
|
||||||
|
const driverBundleEntry = outerEntries.find((entry) => DRIVER_BUNDLE_PATTERN.test(entry.name))
|
||||||
|
const keepDriverDirectories = asArray(keepDriverDirectory)
|
||||||
|
|
||||||
|
if (!driverBundleEntry) {
|
||||||
|
throw new Error(`Playwright driver-bundle jar not found in ${appJarPath}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const innerEntries = readZipEntries(driverBundleEntry.data)
|
||||||
|
let removedDriverEntries = 0
|
||||||
|
let keptDriverEntries = 0
|
||||||
|
|
||||||
|
const trimmedInnerEntries = innerEntries.filter((entry) => {
|
||||||
|
if (!entry.name.startsWith('driver/')) return true
|
||||||
|
if (keepDriverDirectories.some((directory) => entry.name.startsWith(`${directory}/`))) {
|
||||||
|
keptDriverEntries += 1
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
removedDriverEntries += 1
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
|
||||||
|
if (keptDriverEntries === 0) {
|
||||||
|
throw new Error(
|
||||||
|
`No entries kept under ${keepDriverDirectories.join(', ')}; Playwright driver layout may have changed`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const trimmedDriverBundle = createZipBuffer(trimmedInnerEntries.map(cloneEntryForWrite))
|
||||||
|
const rewrittenOuterEntries = outerEntries.map((entry) => {
|
||||||
|
if (entry.name !== driverBundleEntry.name) return cloneEntryForWrite(entry)
|
||||||
|
return {
|
||||||
|
...cloneEntryForWrite(entry),
|
||||||
|
data: trimmedDriverBundle,
|
||||||
|
method: ZIP_STORED,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const rewrittenAppJar = createZipBuffer(rewrittenOuterEntries)
|
||||||
|
fs.writeFileSync(appJarPath, rewrittenAppJar)
|
||||||
|
|
||||||
|
return {
|
||||||
|
beforeBytes: appJarBuffer.length,
|
||||||
|
afterBytes: rewrittenAppJar.length,
|
||||||
|
driverBundleName: driverBundleEntry.name,
|
||||||
|
keptDriverEntries,
|
||||||
|
removedDriverEntries,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function cloneEntryForWrite(entry) {
|
||||||
|
return {
|
||||||
|
name: entry.name,
|
||||||
|
data: Buffer.from(entry.data),
|
||||||
|
method: entry.method,
|
||||||
|
date: entry.date,
|
||||||
|
comment: entry.comment,
|
||||||
|
externalAttributes: entry.externalAttributes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveDriverDirectory(platform, arch) {
|
||||||
|
const normalizedArch = normalizeArch(arch)
|
||||||
|
|
||||||
|
if (platform === 'darwin') {
|
||||||
|
if (normalizedArch === 'arm64') return 'driver/mac-arm64'
|
||||||
|
if (normalizedArch === 'x64') return 'driver/mac'
|
||||||
|
if (normalizedArch === 'universal') return ['driver/mac', 'driver/mac-arm64']
|
||||||
|
}
|
||||||
|
|
||||||
|
if (platform === 'linux') {
|
||||||
|
if (normalizedArch === 'arm64') return 'driver/linux-arm64'
|
||||||
|
if (normalizedArch === 'x64') return 'driver/linux'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (platform === 'win32') {
|
||||||
|
return 'driver/win32_x64'
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(`Unsupported platform/arch for Playwright driver trim: ${platform}/${arch}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
function asArray(value) {
|
||||||
|
return Array.isArray(value) ? value : [value]
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeArch(arch) {
|
||||||
|
if (arch === ARCH_X64 || arch === 'x64') return 'x64'
|
||||||
|
if (arch === ARCH_ARM64 || arch === 'arm64') return 'arm64'
|
||||||
|
if (arch === 'universal' || arch === 4) return 'universal'
|
||||||
|
return String(arch)
|
||||||
|
}
|
||||||
|
|
||||||
|
function readZipEntries(buffer) {
|
||||||
|
const eocdOffset = findEndOfCentralDirectory(buffer)
|
||||||
|
const centralDirectorySize = buffer.readUInt32LE(eocdOffset + 12)
|
||||||
|
const centralDirectoryOffset = buffer.readUInt32LE(eocdOffset + 16)
|
||||||
|
const entries = []
|
||||||
|
|
||||||
|
let offset = centralDirectoryOffset
|
||||||
|
const centralDirectoryEnd = centralDirectoryOffset + centralDirectorySize
|
||||||
|
|
||||||
|
while (offset < centralDirectoryEnd) {
|
||||||
|
const signature = buffer.readUInt32LE(offset)
|
||||||
|
if (signature !== 0x02014b50) {
|
||||||
|
throw new Error(`Invalid central directory signature at offset ${offset}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const flags = buffer.readUInt16LE(offset + 8)
|
||||||
|
const method = buffer.readUInt16LE(offset + 10)
|
||||||
|
const dosTime = buffer.readUInt16LE(offset + 12)
|
||||||
|
const dosDate = buffer.readUInt16LE(offset + 14)
|
||||||
|
const crc = buffer.readUInt32LE(offset + 16)
|
||||||
|
const compressedSize = buffer.readUInt32LE(offset + 20)
|
||||||
|
const uncompressedSize = buffer.readUInt32LE(offset + 24)
|
||||||
|
const fileNameLength = buffer.readUInt16LE(offset + 28)
|
||||||
|
const extraLength = buffer.readUInt16LE(offset + 30)
|
||||||
|
const commentLength = buffer.readUInt16LE(offset + 32)
|
||||||
|
const externalAttributes = buffer.readUInt32LE(offset + 38)
|
||||||
|
const localHeaderOffset = buffer.readUInt32LE(offset + 42)
|
||||||
|
const name = buffer.toString('utf8', offset + 46, offset + 46 + fileNameLength)
|
||||||
|
const comment = buffer.subarray(offset + 46 + fileNameLength + extraLength, offset + 46 + fileNameLength + extraLength + commentLength)
|
||||||
|
|
||||||
|
const localSignature = buffer.readUInt32LE(localHeaderOffset)
|
||||||
|
if (localSignature !== 0x04034b50) {
|
||||||
|
throw new Error(`Invalid local file header signature for ${name}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const localNameLength = buffer.readUInt16LE(localHeaderOffset + 26)
|
||||||
|
const localExtraLength = buffer.readUInt16LE(localHeaderOffset + 28)
|
||||||
|
const dataOffset = localHeaderOffset + 30 + localNameLength + localExtraLength
|
||||||
|
const compressedData = buffer.subarray(dataOffset, dataOffset + compressedSize)
|
||||||
|
|
||||||
|
let data
|
||||||
|
if (method === ZIP_STORED) {
|
||||||
|
data = Buffer.from(compressedData)
|
||||||
|
} else if (method === ZIP_DEFLATED) {
|
||||||
|
data = zlib.inflateRawSync(compressedData)
|
||||||
|
} else {
|
||||||
|
throw new Error(`Unsupported ZIP method ${method} for ${name}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.length !== uncompressedSize) {
|
||||||
|
throw new Error(`Unexpected uncompressed size for ${name}: ${data.length} !== ${uncompressedSize}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
entries.push({
|
||||||
|
name,
|
||||||
|
data,
|
||||||
|
method,
|
||||||
|
flags,
|
||||||
|
crc,
|
||||||
|
date: dosToDate(dosDate, dosTime),
|
||||||
|
comment: Buffer.from(comment),
|
||||||
|
externalAttributes,
|
||||||
|
})
|
||||||
|
|
||||||
|
offset += 46 + fileNameLength + extraLength + commentLength
|
||||||
|
}
|
||||||
|
|
||||||
|
return entries
|
||||||
|
}
|
||||||
|
|
||||||
|
function createZipBuffer(entries) {
|
||||||
|
const localParts = []
|
||||||
|
const centralParts = []
|
||||||
|
let offset = 0
|
||||||
|
|
||||||
|
for (const entry of entries) {
|
||||||
|
const nameBuffer = Buffer.from(entry.name)
|
||||||
|
const data = Buffer.isBuffer(entry.data) ? entry.data : Buffer.from(entry.data || '')
|
||||||
|
const method = entry.method ?? ZIP_DEFLATED
|
||||||
|
const compressedData = method === ZIP_STORED ? data : zlib.deflateRawSync(data)
|
||||||
|
const crc = crc32(data)
|
||||||
|
const { dosDate, dosTime } = dateToDos(entry.date)
|
||||||
|
|
||||||
|
const localHeader = Buffer.alloc(30 + nameBuffer.length)
|
||||||
|
localHeader.writeUInt32LE(0x04034b50, 0)
|
||||||
|
localHeader.writeUInt16LE(20, 4)
|
||||||
|
localHeader.writeUInt16LE(0x0800, 6)
|
||||||
|
localHeader.writeUInt16LE(method, 8)
|
||||||
|
localHeader.writeUInt16LE(dosTime, 10)
|
||||||
|
localHeader.writeUInt16LE(dosDate, 12)
|
||||||
|
localHeader.writeUInt32LE(crc, 14)
|
||||||
|
localHeader.writeUInt32LE(compressedData.length, 18)
|
||||||
|
localHeader.writeUInt32LE(data.length, 22)
|
||||||
|
localHeader.writeUInt16LE(nameBuffer.length, 26)
|
||||||
|
localHeader.writeUInt16LE(0, 28)
|
||||||
|
nameBuffer.copy(localHeader, 30)
|
||||||
|
|
||||||
|
localParts.push(localHeader, compressedData)
|
||||||
|
|
||||||
|
const comment = Buffer.isBuffer(entry.comment) ? entry.comment : Buffer.alloc(0)
|
||||||
|
const centralHeader = Buffer.alloc(46 + nameBuffer.length + comment.length)
|
||||||
|
centralHeader.writeUInt32LE(0x02014b50, 0)
|
||||||
|
centralHeader.writeUInt16LE(20, 4)
|
||||||
|
centralHeader.writeUInt16LE(20, 6)
|
||||||
|
centralHeader.writeUInt16LE(0x0800, 8)
|
||||||
|
centralHeader.writeUInt16LE(method, 10)
|
||||||
|
centralHeader.writeUInt16LE(dosTime, 12)
|
||||||
|
centralHeader.writeUInt16LE(dosDate, 14)
|
||||||
|
centralHeader.writeUInt32LE(crc, 16)
|
||||||
|
centralHeader.writeUInt32LE(compressedData.length, 20)
|
||||||
|
centralHeader.writeUInt32LE(data.length, 24)
|
||||||
|
centralHeader.writeUInt16LE(nameBuffer.length, 28)
|
||||||
|
centralHeader.writeUInt16LE(0, 30)
|
||||||
|
centralHeader.writeUInt16LE(comment.length, 32)
|
||||||
|
centralHeader.writeUInt16LE(0, 34)
|
||||||
|
centralHeader.writeUInt16LE(0, 36)
|
||||||
|
centralHeader.writeUInt32LE(entry.externalAttributes || 0, 38)
|
||||||
|
centralHeader.writeUInt32LE(offset, 42)
|
||||||
|
nameBuffer.copy(centralHeader, 46)
|
||||||
|
comment.copy(centralHeader, 46 + nameBuffer.length)
|
||||||
|
centralParts.push(centralHeader)
|
||||||
|
|
||||||
|
offset += localHeader.length + compressedData.length
|
||||||
|
}
|
||||||
|
|
||||||
|
const centralDirectoryOffset = offset
|
||||||
|
const centralDirectory = Buffer.concat(centralParts)
|
||||||
|
const centralDirectorySize = centralDirectory.length
|
||||||
|
|
||||||
|
const eocd = Buffer.alloc(22)
|
||||||
|
eocd.writeUInt32LE(0x06054b50, 0)
|
||||||
|
eocd.writeUInt16LE(0, 4)
|
||||||
|
eocd.writeUInt16LE(0, 6)
|
||||||
|
eocd.writeUInt16LE(entries.length, 8)
|
||||||
|
eocd.writeUInt16LE(entries.length, 10)
|
||||||
|
eocd.writeUInt32LE(centralDirectorySize, 12)
|
||||||
|
eocd.writeUInt32LE(centralDirectoryOffset, 16)
|
||||||
|
eocd.writeUInt16LE(0, 20)
|
||||||
|
|
||||||
|
return Buffer.concat([...localParts, centralDirectory, eocd])
|
||||||
|
}
|
||||||
|
|
||||||
|
function findEndOfCentralDirectory(buffer) {
|
||||||
|
const minOffset = Math.max(0, buffer.length - 0xffff - 22)
|
||||||
|
for (let offset = buffer.length - 22; offset >= minOffset; offset -= 1) {
|
||||||
|
if (buffer.readUInt32LE(offset) === 0x06054b50) return offset
|
||||||
|
}
|
||||||
|
throw new Error('End of central directory not found')
|
||||||
|
}
|
||||||
|
|
||||||
|
function dateToDos(date) {
|
||||||
|
const value = date instanceof Date ? date : new Date(1980, 0, 1, 0, 0, 0)
|
||||||
|
const year = Math.max(1980, value.getFullYear())
|
||||||
|
return {
|
||||||
|
dosDate: ((year - 1980) << 9) | ((value.getMonth() + 1) << 5) | value.getDate(),
|
||||||
|
dosTime: (value.getHours() << 11) | (value.getMinutes() << 5) | Math.floor(value.getSeconds() / 2),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function dosToDate(dosDate, dosTime) {
|
||||||
|
const day = dosDate & 0x1f
|
||||||
|
const month = (dosDate >> 5) & 0x0f
|
||||||
|
const year = ((dosDate >> 9) & 0x7f) + 1980
|
||||||
|
const second = (dosTime & 0x1f) * 2
|
||||||
|
const minute = (dosTime >> 5) & 0x3f
|
||||||
|
const hour = (dosTime >> 11) & 0x1f
|
||||||
|
return new Date(year, Math.max(0, month - 1), day || 1, hour, minute, second)
|
||||||
|
}
|
||||||
|
|
||||||
|
function crc32(buffer) {
|
||||||
|
let crc = 0xffffffff
|
||||||
|
for (let i = 0; i < buffer.length; i += 1) {
|
||||||
|
crc = CRC_TABLE[(crc ^ buffer[i]) & 0xff] ^ (crc >>> 8)
|
||||||
|
}
|
||||||
|
return (crc ^ 0xffffffff) >>> 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeCrcTable() {
|
||||||
|
const table = new Uint32Array(256)
|
||||||
|
for (let i = 0; i < 256; i += 1) {
|
||||||
|
let value = i
|
||||||
|
for (let bit = 0; bit < 8; bit += 1) {
|
||||||
|
value = value & 1 ? 0xedb88320 ^ (value >>> 1) : value >>> 1
|
||||||
|
}
|
||||||
|
table[i] = value >>> 0
|
||||||
|
}
|
||||||
|
return table
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatBytes(bytes) {
|
||||||
|
return `${(bytes / 1024 / 1024).toFixed(1)} MB`
|
||||||
|
}
|
||||||
|
|
||||||
|
const CRC_TABLE = makeCrcTable()
|
||||||
|
|
||||||
|
module.exports = afterPack
|
||||||
|
module.exports.default = afterPack
|
||||||
|
module.exports.createZipBuffer = createZipBuffer
|
||||||
|
module.exports.readZipEntries = readZipEntries
|
||||||
|
module.exports.resolveDriverDirectory = resolveDriverDirectory
|
||||||
|
module.exports.trimDriverBundleInAppJar = trimDriverBundleInAppJar
|
||||||
|
module.exports.ZIP_STORED = ZIP_STORED
|
||||||
|
module.exports.ZIP_DEFLATED = ZIP_DEFLATED
|
||||||
|
|||||||
@ -0,0 +1,24 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Helper for the obsidian-vault wizard template — lists recently-modified
|
||||||
|
# .md files in a vault. Copied into the new skill's workspace at
|
||||||
|
# ${workspace_root}/${slug}/scripts/helper.sh by SkillBundleMaterializer.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
VAULT="${1:-}"
|
||||||
|
if [[ -z "$VAULT" ]]; then
|
||||||
|
echo "usage: helper.sh <vault-path>"
|
||||||
|
echo "lists *.md files under the vault, sorted by mtime (newest first)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -d "$VAULT" ]]; then
|
||||||
|
echo "vault not found: $VAULT" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
find "$VAULT" -type f -name '*.md' -not -path '*/.*' \
|
||||||
|
-exec stat -f '%m %N' {} + 2>/dev/null \
|
||||||
|
| sort -rn \
|
||||||
|
| head -20 \
|
||||||
|
| awk '{ $1=""; sub(/^ /, ""); print }'
|
||||||
@ -0,0 +1,114 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Search arXiv and display results in a clean format.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python search_arxiv.py "GRPO reinforcement learning"
|
||||||
|
python search_arxiv.py "GRPO reinforcement learning" --max 10
|
||||||
|
python search_arxiv.py "GRPO reinforcement learning" --sort date
|
||||||
|
python search_arxiv.py --author "Yann LeCun" --max 5
|
||||||
|
python search_arxiv.py --category cs.AI --sort date --max 10
|
||||||
|
python search_arxiv.py --id 2402.03300
|
||||||
|
python search_arxiv.py --id 2402.03300,2401.12345
|
||||||
|
"""
|
||||||
|
import sys
|
||||||
|
import urllib.request
|
||||||
|
import urllib.parse
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
NS = {'a': 'http://www.w3.org/2005/Atom'}
|
||||||
|
|
||||||
|
def search(query=None, author=None, category=None, ids=None, max_results=5, sort="relevance"):
|
||||||
|
params = {}
|
||||||
|
|
||||||
|
if ids:
|
||||||
|
params['id_list'] = ids
|
||||||
|
else:
|
||||||
|
parts = []
|
||||||
|
if query:
|
||||||
|
parts.append(f'all:{urllib.parse.quote(query)}')
|
||||||
|
if author:
|
||||||
|
parts.append(f'au:{urllib.parse.quote(author)}')
|
||||||
|
if category:
|
||||||
|
parts.append(f'cat:{category}')
|
||||||
|
if not parts:
|
||||||
|
print("Error: provide a query, --author, --category, or --id")
|
||||||
|
sys.exit(1)
|
||||||
|
params['search_query'] = '+AND+'.join(parts)
|
||||||
|
|
||||||
|
params['max_results'] = str(max_results)
|
||||||
|
|
||||||
|
sort_map = {"relevance": "relevance", "date": "submittedDate", "updated": "lastUpdatedDate"}
|
||||||
|
params['sortBy'] = sort_map.get(sort, sort)
|
||||||
|
params['sortOrder'] = 'descending'
|
||||||
|
|
||||||
|
url = "https://export.arxiv.org/api/query?" + "&".join(f"{k}={v}" for k, v in params.items())
|
||||||
|
|
||||||
|
req = urllib.request.Request(url, headers={'User-Agent': 'MateClaw/1.0'})
|
||||||
|
with urllib.request.urlopen(req, timeout=15) as resp:
|
||||||
|
data = resp.read()
|
||||||
|
|
||||||
|
root = ET.fromstring(data)
|
||||||
|
entries = root.findall('a:entry', NS)
|
||||||
|
|
||||||
|
if not entries:
|
||||||
|
print("No results found.")
|
||||||
|
return
|
||||||
|
|
||||||
|
total = root.find('{http://a9.com/-/spec/opensearch/1.1/}totalResults')
|
||||||
|
if total is not None:
|
||||||
|
print(f"Found {total.text} results (showing {len(entries)})\n")
|
||||||
|
|
||||||
|
for i, entry in enumerate(entries):
|
||||||
|
title = entry.find('a:title', NS).text.strip().replace('\n', ' ')
|
||||||
|
raw_id = entry.find('a:id', NS).text.strip()
|
||||||
|
full_id = raw_id.split('/abs/')[-1] if '/abs/' in raw_id else raw_id
|
||||||
|
arxiv_id = full_id.split('v')[0] # base ID for links
|
||||||
|
published = entry.find('a:published', NS).text[:10]
|
||||||
|
updated = entry.find('a:updated', NS).text[:10]
|
||||||
|
authors = ', '.join(a.find('a:name', NS).text for a in entry.findall('a:author', NS))
|
||||||
|
summary = entry.find('a:summary', NS).text.strip().replace('\n', ' ')
|
||||||
|
cats = ', '.join(c.get('term') for c in entry.findall('a:category', NS))
|
||||||
|
|
||||||
|
version = full_id[len(arxiv_id):] if full_id != arxiv_id else ""
|
||||||
|
print(f"{i+1}. {title}")
|
||||||
|
print(f" ID: {arxiv_id}{version} | Published: {published} | Updated: {updated}")
|
||||||
|
print(f" Authors: {authors}")
|
||||||
|
print(f" Categories: {cats}")
|
||||||
|
print(f" Abstract: {summary[:300]}{'...' if len(summary) > 300 else ''}")
|
||||||
|
print(f" Links: https://arxiv.org/abs/{arxiv_id} | https://arxiv.org/pdf/{arxiv_id}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
args = sys.argv[1:]
|
||||||
|
if not args or args[0] in ("-h", "--help"):
|
||||||
|
print(__doc__)
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
query = None
|
||||||
|
author = None
|
||||||
|
category = None
|
||||||
|
ids = None
|
||||||
|
max_results = 5
|
||||||
|
sort = "relevance"
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
positional = []
|
||||||
|
while i < len(args):
|
||||||
|
if args[i] == "--max" and i + 1 < len(args):
|
||||||
|
max_results = int(args[i + 1]); i += 2
|
||||||
|
elif args[i] == "--sort" and i + 1 < len(args):
|
||||||
|
sort = args[i + 1]; i += 2
|
||||||
|
elif args[i] == "--author" and i + 1 < len(args):
|
||||||
|
author = args[i + 1]; i += 2
|
||||||
|
elif args[i] == "--category" and i + 1 < len(args):
|
||||||
|
category = args[i + 1]; i += 2
|
||||||
|
elif args[i] == "--id" and i + 1 < len(args):
|
||||||
|
ids = args[i + 1]; i += 2
|
||||||
|
else:
|
||||||
|
positional.append(args[i]); i += 1
|
||||||
|
|
||||||
|
if positional:
|
||||||
|
query = " ".join(positional)
|
||||||
|
|
||||||
|
search(query=query, author=author, category=category, ids=ids, max_results=max_results, sort=sort)
|
||||||
@ -0,0 +1,299 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Heuristic scorer for AI-writing traces in Chinese text (stdlib only).
|
||||||
|
|
||||||
|
Reads a single JSON argument from argv[1], or from stdin if no argument
|
||||||
|
is given:
|
||||||
|
|
||||||
|
{"text": "...", "platform": "gzh" | "xhs"}
|
||||||
|
|
||||||
|
Prints a JSON report to stdout:
|
||||||
|
|
||||||
|
{
|
||||||
|
"score": 0-100, # higher = more AI-like
|
||||||
|
"signals": [ {name, value, weight, note}, ... ],
|
||||||
|
"spans": ["offending substring", ...],
|
||||||
|
"verdict": "human-like" | "some-ai" | "strong-ai"
|
||||||
|
}
|
||||||
|
|
||||||
|
The score is a deterministic, explainable quality signal built from
|
||||||
|
surface features of the text. It is a writing-quality heuristic to guide
|
||||||
|
rewriting, NOT a guarantee about the output of any external AI detector.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
|
||||||
|
# --- Feature vocabularies ---------------------------------------------------
|
||||||
|
|
||||||
|
# Discourse connectors: a few are natural, but a high density reads as
|
||||||
|
# machine-organized "listy" prose.
|
||||||
|
CONNECTORS = [
|
||||||
|
"首先", "其次", "再次", "然后", "最后", "综上所述", "总而言之",
|
||||||
|
"总的来说", "总体而言", "值得注意的是", "需要注意的是",
|
||||||
|
"由此可见", "换句话说", "简而言之", "一方面", "另一方面",
|
||||||
|
"此外", "与此同时", "不仅如此",
|
||||||
|
]
|
||||||
|
|
||||||
|
# Cliché templates. Entries with "[^...]{0,n}" allow a bounded gap so
|
||||||
|
# "在<任意短语>的今天" and friends match without crossing a clause boundary.
|
||||||
|
CLICHE_PATTERNS = [
|
||||||
|
r"在[^,。!?;\n]{0,12}的今天",
|
||||||
|
r"在这个[^,。!?;\n]{0,10}的时代",
|
||||||
|
r"随着[^,。!?;\n]{0,16}的(发展|到来|普及|推进)",
|
||||||
|
r"让我们",
|
||||||
|
r"赋能",
|
||||||
|
r"注入(新的)?活力",
|
||||||
|
r"[^,。!?;\n]{0,8}是[^,。!?;\n]{0,6}的关键",
|
||||||
|
r"众所周知",
|
||||||
|
r"不难发现",
|
||||||
|
r"不可否认",
|
||||||
|
r"数字化转型",
|
||||||
|
r"深度融合",
|
||||||
|
r"保驾护航",
|
||||||
|
r"打造[^,。!?;\n]{0,6}新(生态|格局|范式|标杆)",
|
||||||
|
r"开启[^,。!?;\n]{0,6}新(篇章|征程)",
|
||||||
|
]
|
||||||
|
|
||||||
|
# Concreteness markers: first-person voice, digits, and time words signal
|
||||||
|
# lived, specific writing rather than abstract summary.
|
||||||
|
FIRST_PERSON = ["我们", "咱们", "我", "咱"]
|
||||||
|
TIME_WORDS = [
|
||||||
|
"今天", "昨天", "明天", "前天", "后天", "上周", "下周", "上午",
|
||||||
|
"下午", "早上", "中午", "晚上", "凌晨", "刚才", "去年", "今年",
|
||||||
|
"星期", "周一", "周二", "周三", "周四", "周五", "周六", "周日",
|
||||||
|
"分钟", "小时", "点钟",
|
||||||
|
]
|
||||||
|
|
||||||
|
CJK_RE = re.compile(r"[一-鿿]")
|
||||||
|
SENT_SPLIT_RE = re.compile(r"[。!?;!?;\n]+")
|
||||||
|
DIGIT_RE = re.compile(r"[0-90-9]")
|
||||||
|
DASH_RE = re.compile(r"[—–\-]{1,2}|•|·")
|
||||||
|
|
||||||
|
# Per-platform signal weights. They sum to 100 within each platform.
|
||||||
|
# xhs (Xiaohongshu) prizes short, bursty fragments, so sentence-length and
|
||||||
|
# paragraph-uniformity carry less weight there.
|
||||||
|
WEIGHTS = {
|
||||||
|
"gzh": {
|
||||||
|
"cliche": 28, "connector": 26, "concreteness": 14,
|
||||||
|
"burstiness": 12, "list_dash": 8, "para_uniform": 12,
|
||||||
|
},
|
||||||
|
"xhs": {
|
||||||
|
"cliche": 32, "connector": 24, "concreteness": 20,
|
||||||
|
"burstiness": 6, "list_dash": 8, "para_uniform": 10,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
NEUTRAL = 0.3 # sub-score used when a signal lacks enough data
|
||||||
|
MIN_SENTS_FOR_BURST = 4 # burstiness needs enough sentences to be meaningful
|
||||||
|
MIN_PARAS_FOR_UNIFORM = 3
|
||||||
|
|
||||||
|
|
||||||
|
def clamp01(x):
|
||||||
|
"""Clamp a float into the [0, 1] range."""
|
||||||
|
if x < 0.0:
|
||||||
|
return 0.0
|
||||||
|
if x > 1.0:
|
||||||
|
return 1.0
|
||||||
|
return x
|
||||||
|
|
||||||
|
|
||||||
|
def cjk_len(s):
|
||||||
|
"""Count CJK characters in a string."""
|
||||||
|
return len(CJK_RE.findall(s))
|
||||||
|
|
||||||
|
|
||||||
|
def std(values):
|
||||||
|
"""Population standard deviation of a list of numbers."""
|
||||||
|
n = len(values)
|
||||||
|
if n == 0:
|
||||||
|
return 0.0
|
||||||
|
mean = sum(values) / n
|
||||||
|
variance = sum((v - mean) ** 2 for v in values) / n
|
||||||
|
return variance ** 0.5
|
||||||
|
|
||||||
|
|
||||||
|
def count_occurrences(text, needles):
|
||||||
|
"""Total non-overlapping occurrences of any needle, plus matched spans."""
|
||||||
|
total = 0
|
||||||
|
spans = []
|
||||||
|
for needle in needles:
|
||||||
|
start = 0
|
||||||
|
while True:
|
||||||
|
idx = text.find(needle, start)
|
||||||
|
if idx < 0:
|
||||||
|
break
|
||||||
|
total += 1
|
||||||
|
spans.append(needle)
|
||||||
|
start = idx + len(needle)
|
||||||
|
return total, spans
|
||||||
|
|
||||||
|
|
||||||
|
def score_text(text, platform):
|
||||||
|
"""Compute the AI-trace report for a piece of text."""
|
||||||
|
weights = WEIGHTS.get(platform, WEIGHTS["gzh"])
|
||||||
|
signals = []
|
||||||
|
spans = []
|
||||||
|
|
||||||
|
total_cjk = cjk_len(text)
|
||||||
|
# Guard against empty / whitespace-only input.
|
||||||
|
if total_cjk == 0:
|
||||||
|
return {
|
||||||
|
"score": 0,
|
||||||
|
"signals": [],
|
||||||
|
"spans": [],
|
||||||
|
"verdict": "human-like",
|
||||||
|
}
|
||||||
|
per100 = total_cjk / 100.0 # divisor to express "hits per 100 CJK chars"
|
||||||
|
|
||||||
|
sentences = [s for s in SENT_SPLIT_RE.split(text) if s.strip()]
|
||||||
|
|
||||||
|
# 1) Connector density -------------------------------------------------
|
||||||
|
conn_hits, conn_spans = count_occurrences(text, CONNECTORS)
|
||||||
|
conn_value = clamp01((conn_hits / per100) / 2.5) # target ~2.5 / 100 chars
|
||||||
|
signals.append({
|
||||||
|
"name": "connector_density",
|
||||||
|
"value": round(conn_value, 3),
|
||||||
|
"weight": weights["connector"],
|
||||||
|
"note": f"{conn_hits} discourse connectors",
|
||||||
|
})
|
||||||
|
spans.extend(conn_spans)
|
||||||
|
|
||||||
|
# 2) Cliché phrase hits ------------------------------------------------
|
||||||
|
cliche_hits = 0
|
||||||
|
for pattern in CLICHE_PATTERNS:
|
||||||
|
for m in re.finditer(pattern, text):
|
||||||
|
cliche_hits += 1
|
||||||
|
spans.append(m.group(0))
|
||||||
|
cliche_value = clamp01((cliche_hits / per100) / 1.2) # target ~1.2 / 100
|
||||||
|
signals.append({
|
||||||
|
"name": "cliche_phrases",
|
||||||
|
"value": round(cliche_value, 3),
|
||||||
|
"weight": weights["cliche"],
|
||||||
|
"note": f"{cliche_hits} cliché template hits",
|
||||||
|
})
|
||||||
|
|
||||||
|
# 3) Concreteness deficit ----------------------------------------------
|
||||||
|
digits = len(DIGIT_RE.findall(text))
|
||||||
|
fp_hits, _ = count_occurrences(text, FIRST_PERSON)
|
||||||
|
time_hits, _ = count_occurrences(text, TIME_WORDS)
|
||||||
|
concrete_raw = digits + fp_hits + time_hits
|
||||||
|
richness = clamp01((concrete_raw / per100) / 6.0) # target ~6 / 100 chars
|
||||||
|
concrete_value = 1.0 - richness # deficit: less concreteness = more AI
|
||||||
|
signals.append({
|
||||||
|
"name": "concreteness_deficit",
|
||||||
|
"value": round(concrete_value, 3),
|
||||||
|
"weight": weights["concreteness"],
|
||||||
|
"note": f"{digits} digits, {fp_hits} first-person, {time_hits} time words",
|
||||||
|
})
|
||||||
|
|
||||||
|
# 4) Sentence-length burstiness ----------------------------------------
|
||||||
|
lengths = [cjk_len(s) for s in sentences]
|
||||||
|
lengths = [n for n in lengths if n > 0]
|
||||||
|
if len(lengths) >= MIN_SENTS_FOR_BURST:
|
||||||
|
mean = sum(lengths) / len(lengths)
|
||||||
|
cv = (std(lengths) / mean) if mean > 0 else 0.0
|
||||||
|
# Low coefficient of variation = uniform lengths = more AI-like.
|
||||||
|
burst_value = clamp01(1.0 - cv / 0.5)
|
||||||
|
note = f"{len(lengths)} sentences, cv={round(cv, 3)}"
|
||||||
|
else:
|
||||||
|
burst_value = NEUTRAL
|
||||||
|
note = f"{len(lengths)} sentences (too few to judge)"
|
||||||
|
signals.append({
|
||||||
|
"name": "sentence_burstiness",
|
||||||
|
"value": round(burst_value, 3),
|
||||||
|
"weight": weights["burstiness"],
|
||||||
|
"note": note,
|
||||||
|
})
|
||||||
|
|
||||||
|
# 5) List / dash overuse -----------------------------------------------
|
||||||
|
dash_hits = len(DASH_RE.findall(text))
|
||||||
|
bullet_lines = sum(
|
||||||
|
1 for line in text.splitlines()
|
||||||
|
if re.match(r"^\s*([-*•·\d]+[.、)]?)\s+", line)
|
||||||
|
)
|
||||||
|
list_raw = dash_hits + bullet_lines
|
||||||
|
list_value = clamp01((list_raw / per100) / 2.0) # target ~2 / 100 chars
|
||||||
|
signals.append({
|
||||||
|
"name": "list_dash_overuse",
|
||||||
|
"value": round(list_value, 3),
|
||||||
|
"weight": weights["list_dash"],
|
||||||
|
"note": f"{dash_hits} dashes, {bullet_lines} bullet lines",
|
||||||
|
})
|
||||||
|
|
||||||
|
# 6) Paragraph-length uniformity ---------------------------------------
|
||||||
|
paragraphs = [p for p in re.split(r"\n\s*\n", text) if p.strip()]
|
||||||
|
para_lengths = [cjk_len(p) for p in paragraphs]
|
||||||
|
para_lengths = [n for n in para_lengths if n > 0]
|
||||||
|
if len(para_lengths) >= MIN_PARAS_FOR_UNIFORM:
|
||||||
|
mean = sum(para_lengths) / len(para_lengths)
|
||||||
|
cv = (std(para_lengths) / mean) if mean > 0 else 0.0
|
||||||
|
para_value = clamp01(1.0 - cv / 0.5)
|
||||||
|
note = f"{len(para_lengths)} paragraphs, cv={round(cv, 3)}"
|
||||||
|
else:
|
||||||
|
para_value = NEUTRAL
|
||||||
|
note = f"{len(para_lengths)} paragraphs (too few to judge)"
|
||||||
|
signals.append({
|
||||||
|
"name": "paragraph_uniformity",
|
||||||
|
"value": round(para_value, 3),
|
||||||
|
"weight": weights["para_uniform"],
|
||||||
|
"note": note,
|
||||||
|
})
|
||||||
|
|
||||||
|
# --- Aggregate --------------------------------------------------------
|
||||||
|
score = sum(s["value"] * s["weight"] for s in signals)
|
||||||
|
score = int(round(clamp01(score / 100.0) * 100))
|
||||||
|
|
||||||
|
if score < 40:
|
||||||
|
verdict = "human-like"
|
||||||
|
elif score < 60:
|
||||||
|
verdict = "some-ai"
|
||||||
|
else:
|
||||||
|
verdict = "strong-ai"
|
||||||
|
|
||||||
|
# De-duplicate spans while preserving order, and cap the list length.
|
||||||
|
seen = set()
|
||||||
|
unique_spans = []
|
||||||
|
for sp in spans:
|
||||||
|
if sp not in seen:
|
||||||
|
seen.add(sp)
|
||||||
|
unique_spans.append(sp)
|
||||||
|
unique_spans = unique_spans[:30]
|
||||||
|
|
||||||
|
return {
|
||||||
|
"score": score,
|
||||||
|
"signals": signals,
|
||||||
|
"spans": unique_spans,
|
||||||
|
"verdict": verdict,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def load_input():
|
||||||
|
"""Load the JSON payload from argv[1] or stdin."""
|
||||||
|
if len(sys.argv) > 1 and sys.argv[1].strip():
|
||||||
|
raw = sys.argv[1]
|
||||||
|
else:
|
||||||
|
raw = sys.stdin.read()
|
||||||
|
if not raw or not raw.strip():
|
||||||
|
return {"text": "", "platform": "gzh"}
|
||||||
|
return json.loads(raw)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
try:
|
||||||
|
payload = load_input()
|
||||||
|
except (ValueError, json.JSONDecodeError) as exc:
|
||||||
|
print(json.dumps({"error": f"invalid JSON input: {exc}"}, ensure_ascii=False))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
text = payload.get("text", "") or ""
|
||||||
|
platform = payload.get("platform", "gzh") or "gzh"
|
||||||
|
if platform not in WEIGHTS:
|
||||||
|
platform = "gzh"
|
||||||
|
|
||||||
|
report = score_text(text, platform)
|
||||||
|
print(json.dumps(report, ensure_ascii=False))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
1
mateclaw-server/src/main/resources/skills/docx/scripts/__init__.py
Executable file
1
mateclaw-server/src/main/resources/skills/docx/scripts/__init__.py
Executable file
@ -0,0 +1 @@
|
|||||||
|
|
||||||
138
mateclaw-server/src/main/resources/skills/docx/scripts/accept_changes.py
Executable file
138
mateclaw-server/src/main/resources/skills/docx/scripts/accept_changes.py
Executable file
@ -0,0 +1,138 @@
|
|||||||
|
"""Accept all tracked changes in a DOCX file using LibreOffice.
|
||||||
|
|
||||||
|
Requires LibreOffice (soffice) to be installed.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import logging
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from office.soffice import get_soffice_cmd, get_soffice_env
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
LIBREOFFICE_PROFILE = str(Path(tempfile.gettempdir()) / "libreoffice_docx_profile")
|
||||||
|
MACRO_DIR = str(Path(LIBREOFFICE_PROFILE) / "user" / "basic" / "Standard")
|
||||||
|
|
||||||
|
ACCEPT_CHANGES_MACRO = """<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
|
||||||
|
<script:module xmlns:script="http://openoffice.org/2000/script" script:name="Module1" script:language="StarBasic">
|
||||||
|
Sub AcceptAllTrackedChanges()
|
||||||
|
Dim document As Object
|
||||||
|
Dim dispatcher As Object
|
||||||
|
|
||||||
|
document = ThisComponent.CurrentController.Frame
|
||||||
|
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
|
||||||
|
|
||||||
|
dispatcher.executeDispatch(document, ".uno:AcceptAllTrackedChanges", "", 0, Array())
|
||||||
|
ThisComponent.store()
|
||||||
|
ThisComponent.close(True)
|
||||||
|
End Sub
|
||||||
|
</script:module>"""
|
||||||
|
|
||||||
|
|
||||||
|
def accept_changes(
|
||||||
|
input_file: str,
|
||||||
|
output_file: str,
|
||||||
|
) -> tuple[None, str]:
|
||||||
|
input_path = Path(input_file)
|
||||||
|
output_path = Path(output_file)
|
||||||
|
|
||||||
|
if not input_path.exists():
|
||||||
|
return None, f"Error: Input file not found: {input_file}"
|
||||||
|
|
||||||
|
if not input_path.suffix.lower() == ".docx":
|
||||||
|
return None, f"Error: Input file is not a DOCX file: {input_file}"
|
||||||
|
|
||||||
|
try:
|
||||||
|
output_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
shutil.copy2(input_path, output_path)
|
||||||
|
except Exception as e:
|
||||||
|
return None, f"Error: Failed to copy input file to output location: {e}"
|
||||||
|
|
||||||
|
if not _setup_libreoffice_macro():
|
||||||
|
return None, "Error: Failed to setup LibreOffice macro"
|
||||||
|
|
||||||
|
profile_uri = Path(LIBREOFFICE_PROFILE).as_uri()
|
||||||
|
cmd = [
|
||||||
|
get_soffice_cmd(),
|
||||||
|
"--headless",
|
||||||
|
f"-env:UserInstallation={profile_uri}",
|
||||||
|
"--norestore",
|
||||||
|
"vnd.sun.star.script:Standard.Module1.AcceptAllTrackedChanges?language=Basic&location=application",
|
||||||
|
str(output_path.absolute()),
|
||||||
|
]
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = subprocess.run(
|
||||||
|
cmd,
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
timeout=30,
|
||||||
|
check=False,
|
||||||
|
env=get_soffice_env(),
|
||||||
|
)
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
return (
|
||||||
|
None,
|
||||||
|
f"Successfully accepted all tracked changes: {input_file} -> {output_file}",
|
||||||
|
)
|
||||||
|
|
||||||
|
if result.returncode != 0:
|
||||||
|
return None, f"Error: LibreOffice failed: {result.stderr}"
|
||||||
|
|
||||||
|
return (
|
||||||
|
None,
|
||||||
|
f"Successfully accepted all tracked changes: {input_file} -> {output_file}",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _setup_libreoffice_macro() -> bool:
|
||||||
|
macro_dir = Path(MACRO_DIR)
|
||||||
|
macro_file = macro_dir / "Module1.xba"
|
||||||
|
|
||||||
|
if macro_file.exists() and "AcceptAllTrackedChanges" in macro_file.read_text():
|
||||||
|
return True
|
||||||
|
|
||||||
|
if not macro_dir.exists():
|
||||||
|
profile_uri = Path(LIBREOFFICE_PROFILE).as_uri()
|
||||||
|
subprocess.run(
|
||||||
|
[
|
||||||
|
get_soffice_cmd(),
|
||||||
|
"--headless",
|
||||||
|
f"-env:UserInstallation={profile_uri}",
|
||||||
|
"--terminate_after_init",
|
||||||
|
],
|
||||||
|
capture_output=True,
|
||||||
|
timeout=10,
|
||||||
|
check=False,
|
||||||
|
env=get_soffice_env(),
|
||||||
|
)
|
||||||
|
macro_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
try:
|
||||||
|
macro_file.write_text(ACCEPT_CHANGES_MACRO)
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Failed to setup LibreOffice macro: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Accept all tracked changes in a DOCX file"
|
||||||
|
)
|
||||||
|
parser.add_argument("input_file", help="Input DOCX file with tracked changes")
|
||||||
|
parser.add_argument(
|
||||||
|
"output_file", help="Output DOCX file (clean, no tracked changes)"
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
_, message = accept_changes(args.input_file, args.output_file)
|
||||||
|
print(message)
|
||||||
|
|
||||||
|
if "Error" in message:
|
||||||
|
raise SystemExit(1)
|
||||||
318
mateclaw-server/src/main/resources/skills/docx/scripts/comment.py
Executable file
318
mateclaw-server/src/main/resources/skills/docx/scripts/comment.py
Executable file
@ -0,0 +1,318 @@
|
|||||||
|
"""Add comments to DOCX documents.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python comment.py unpacked/ 0 "Comment text"
|
||||||
|
python comment.py unpacked/ 1 "Reply text" --parent 0
|
||||||
|
|
||||||
|
Text should be pre-escaped XML (e.g., & for &, ’ for smart quotes).
|
||||||
|
|
||||||
|
After running, add markers to document.xml:
|
||||||
|
<w:commentRangeStart w:id="0"/>
|
||||||
|
... commented content ...
|
||||||
|
<w:commentRangeEnd w:id="0"/>
|
||||||
|
<w:r><w:rPr><w:rStyle w:val="CommentReference"/></w:rPr><w:commentReference w:id="0"/></w:r>
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import random
|
||||||
|
import shutil
|
||||||
|
import sys
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import defusedxml.minidom
|
||||||
|
|
||||||
|
TEMPLATE_DIR = Path(__file__).parent / "templates"
|
||||||
|
NS = {
|
||||||
|
"w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
|
||||||
|
"w14": "http://schemas.microsoft.com/office/word/2010/wordml",
|
||||||
|
"w15": "http://schemas.microsoft.com/office/word/2012/wordml",
|
||||||
|
"w16cid": "http://schemas.microsoft.com/office/word/2016/wordml/cid",
|
||||||
|
"w16cex": "http://schemas.microsoft.com/office/word/2018/wordml/cex",
|
||||||
|
}
|
||||||
|
|
||||||
|
COMMENT_XML = """\
|
||||||
|
<w:comment w:id="{id}" w:author="{author}" w:date="{date}" w:initials="{initials}">
|
||||||
|
<w:p w14:paraId="{para_id}" w14:textId="77777777">
|
||||||
|
<w:r>
|
||||||
|
<w:rPr><w:rStyle w:val="CommentReference"/></w:rPr>
|
||||||
|
<w:annotationRef/>
|
||||||
|
</w:r>
|
||||||
|
<w:r>
|
||||||
|
<w:rPr>
|
||||||
|
<w:color w:val="000000"/>
|
||||||
|
<w:sz w:val="20"/>
|
||||||
|
<w:szCs w:val="20"/>
|
||||||
|
</w:rPr>
|
||||||
|
<w:t>{text}</w:t>
|
||||||
|
</w:r>
|
||||||
|
</w:p>
|
||||||
|
</w:comment>"""
|
||||||
|
|
||||||
|
COMMENT_MARKER_TEMPLATE = """
|
||||||
|
Add to document.xml (markers must be direct children of w:p, never inside w:r):
|
||||||
|
<w:commentRangeStart w:id="{cid}"/>
|
||||||
|
<w:r>...</w:r>
|
||||||
|
<w:commentRangeEnd w:id="{cid}"/>
|
||||||
|
<w:r><w:rPr><w:rStyle w:val="CommentReference"/></w:rPr><w:commentReference w:id="{cid}"/></w:r>"""
|
||||||
|
|
||||||
|
REPLY_MARKER_TEMPLATE = """
|
||||||
|
Nest markers inside parent {pid}'s markers (markers must be direct children of w:p, never inside w:r):
|
||||||
|
<w:commentRangeStart w:id="{pid}"/><w:commentRangeStart w:id="{cid}"/>
|
||||||
|
<w:r>...</w:r>
|
||||||
|
<w:commentRangeEnd w:id="{cid}"/><w:commentRangeEnd w:id="{pid}"/>
|
||||||
|
<w:r><w:rPr><w:rStyle w:val="CommentReference"/></w:rPr><w:commentReference w:id="{pid}"/></w:r>
|
||||||
|
<w:r><w:rPr><w:rStyle w:val="CommentReference"/></w:rPr><w:commentReference w:id="{cid}"/></w:r>"""
|
||||||
|
|
||||||
|
|
||||||
|
def _generate_hex_id() -> str:
|
||||||
|
return f"{random.randint(0, 0x7FFFFFFE):08X}"
|
||||||
|
|
||||||
|
|
||||||
|
SMART_QUOTE_ENTITIES = {
|
||||||
|
"\u201c": "“",
|
||||||
|
"\u201d": "”",
|
||||||
|
"\u2018": "‘",
|
||||||
|
"\u2019": "’",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _encode_smart_quotes(text: str) -> str:
|
||||||
|
for char, entity in SMART_QUOTE_ENTITIES.items():
|
||||||
|
text = text.replace(char, entity)
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
def _append_xml(xml_path: Path, root_tag: str, content: str) -> None:
|
||||||
|
dom = defusedxml.minidom.parseString(xml_path.read_text(encoding="utf-8"))
|
||||||
|
root = dom.getElementsByTagName(root_tag)[0]
|
||||||
|
ns_attrs = " ".join(f'xmlns:{k}="{v}"' for k, v in NS.items())
|
||||||
|
wrapper_dom = defusedxml.minidom.parseString(f"<root {ns_attrs}>{content}</root>")
|
||||||
|
for child in wrapper_dom.documentElement.childNodes:
|
||||||
|
if child.nodeType == child.ELEMENT_NODE:
|
||||||
|
root.appendChild(dom.importNode(child, True))
|
||||||
|
output = _encode_smart_quotes(dom.toxml(encoding="UTF-8").decode("utf-8"))
|
||||||
|
xml_path.write_text(output, encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
def _find_para_id(comments_path: Path, comment_id: int) -> str | None:
|
||||||
|
dom = defusedxml.minidom.parseString(comments_path.read_text(encoding="utf-8"))
|
||||||
|
for c in dom.getElementsByTagName("w:comment"):
|
||||||
|
if c.getAttribute("w:id") == str(comment_id):
|
||||||
|
for p in c.getElementsByTagName("w:p"):
|
||||||
|
if pid := p.getAttribute("w14:paraId"):
|
||||||
|
return pid
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _get_next_rid(rels_path: Path) -> int:
|
||||||
|
dom = defusedxml.minidom.parseString(rels_path.read_text(encoding="utf-8"))
|
||||||
|
max_rid = 0
|
||||||
|
for rel in dom.getElementsByTagName("Relationship"):
|
||||||
|
rid = rel.getAttribute("Id")
|
||||||
|
if rid and rid.startswith("rId"):
|
||||||
|
try:
|
||||||
|
max_rid = max(max_rid, int(rid[3:]))
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
return max_rid + 1
|
||||||
|
|
||||||
|
|
||||||
|
def _has_relationship(rels_path: Path, target: str) -> bool:
|
||||||
|
dom = defusedxml.minidom.parseString(rels_path.read_text(encoding="utf-8"))
|
||||||
|
for rel in dom.getElementsByTagName("Relationship"):
|
||||||
|
if rel.getAttribute("Target") == target:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _has_content_type(ct_path: Path, part_name: str) -> bool:
|
||||||
|
dom = defusedxml.minidom.parseString(ct_path.read_text(encoding="utf-8"))
|
||||||
|
for override in dom.getElementsByTagName("Override"):
|
||||||
|
if override.getAttribute("PartName") == part_name:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _ensure_comment_relationships(unpacked_dir: Path) -> None:
|
||||||
|
rels_path = unpacked_dir / "word" / "_rels" / "document.xml.rels"
|
||||||
|
if not rels_path.exists():
|
||||||
|
return
|
||||||
|
|
||||||
|
if _has_relationship(rels_path, "comments.xml"):
|
||||||
|
return
|
||||||
|
|
||||||
|
dom = defusedxml.minidom.parseString(rels_path.read_text(encoding="utf-8"))
|
||||||
|
root = dom.documentElement
|
||||||
|
next_rid = _get_next_rid(rels_path)
|
||||||
|
|
||||||
|
rels = [
|
||||||
|
(
|
||||||
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments",
|
||||||
|
"comments.xml",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"http://schemas.microsoft.com/office/2011/relationships/commentsExtended",
|
||||||
|
"commentsExtended.xml",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"http://schemas.microsoft.com/office/2016/09/relationships/commentsIds",
|
||||||
|
"commentsIds.xml",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"http://schemas.microsoft.com/office/2018/08/relationships/commentsExtensible",
|
||||||
|
"commentsExtensible.xml",
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
for rel_type, target in rels:
|
||||||
|
rel = dom.createElement("Relationship")
|
||||||
|
rel.setAttribute("Id", f"rId{next_rid}")
|
||||||
|
rel.setAttribute("Type", rel_type)
|
||||||
|
rel.setAttribute("Target", target)
|
||||||
|
root.appendChild(rel)
|
||||||
|
next_rid += 1
|
||||||
|
|
||||||
|
rels_path.write_bytes(dom.toxml(encoding="UTF-8"))
|
||||||
|
|
||||||
|
|
||||||
|
def _ensure_comment_content_types(unpacked_dir: Path) -> None:
|
||||||
|
ct_path = unpacked_dir / "[Content_Types].xml"
|
||||||
|
if not ct_path.exists():
|
||||||
|
return
|
||||||
|
|
||||||
|
if _has_content_type(ct_path, "/word/comments.xml"):
|
||||||
|
return
|
||||||
|
|
||||||
|
dom = defusedxml.minidom.parseString(ct_path.read_text(encoding="utf-8"))
|
||||||
|
root = dom.documentElement
|
||||||
|
|
||||||
|
overrides = [
|
||||||
|
(
|
||||||
|
"/word/comments.xml",
|
||||||
|
"application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"/word/commentsExtended.xml",
|
||||||
|
"application/vnd.openxmlformats-officedocument.wordprocessingml.commentsExtended+xml",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"/word/commentsIds.xml",
|
||||||
|
"application/vnd.openxmlformats-officedocument.wordprocessingml.commentsIds+xml",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"/word/commentsExtensible.xml",
|
||||||
|
"application/vnd.openxmlformats-officedocument.wordprocessingml.commentsExtensible+xml",
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
for part_name, content_type in overrides:
|
||||||
|
override = dom.createElement("Override")
|
||||||
|
override.setAttribute("PartName", part_name)
|
||||||
|
override.setAttribute("ContentType", content_type)
|
||||||
|
root.appendChild(override)
|
||||||
|
|
||||||
|
ct_path.write_bytes(dom.toxml(encoding="UTF-8"))
|
||||||
|
|
||||||
|
|
||||||
|
def add_comment(
|
||||||
|
unpacked_dir: str,
|
||||||
|
comment_id: int,
|
||||||
|
text: str,
|
||||||
|
author: str = "Claude",
|
||||||
|
initials: str = "C",
|
||||||
|
parent_id: int | None = None,
|
||||||
|
) -> tuple[str, str]:
|
||||||
|
word = Path(unpacked_dir) / "word"
|
||||||
|
if not word.exists():
|
||||||
|
return "", f"Error: {word} not found"
|
||||||
|
|
||||||
|
para_id, durable_id = _generate_hex_id(), _generate_hex_id()
|
||||||
|
ts = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||||
|
|
||||||
|
comments = word / "comments.xml"
|
||||||
|
first_comment = not comments.exists()
|
||||||
|
if first_comment:
|
||||||
|
shutil.copy(TEMPLATE_DIR / "comments.xml", comments)
|
||||||
|
_ensure_comment_relationships(Path(unpacked_dir))
|
||||||
|
_ensure_comment_content_types(Path(unpacked_dir))
|
||||||
|
_append_xml(
|
||||||
|
comments,
|
||||||
|
"w:comments",
|
||||||
|
COMMENT_XML.format(
|
||||||
|
id=comment_id,
|
||||||
|
author=author,
|
||||||
|
date=ts,
|
||||||
|
initials=initials,
|
||||||
|
para_id=para_id,
|
||||||
|
text=text,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
ext = word / "commentsExtended.xml"
|
||||||
|
if not ext.exists():
|
||||||
|
shutil.copy(TEMPLATE_DIR / "commentsExtended.xml", ext)
|
||||||
|
if parent_id is not None:
|
||||||
|
parent_para = _find_para_id(comments, parent_id)
|
||||||
|
if not parent_para:
|
||||||
|
return "", f"Error: Parent comment {parent_id} not found"
|
||||||
|
_append_xml(
|
||||||
|
ext,
|
||||||
|
"w15:commentsEx",
|
||||||
|
f'<w15:commentEx w15:paraId="{para_id}" w15:paraIdParent="{parent_para}" w15:done="0"/>',
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
_append_xml(
|
||||||
|
ext,
|
||||||
|
"w15:commentsEx",
|
||||||
|
f'<w15:commentEx w15:paraId="{para_id}" w15:done="0"/>',
|
||||||
|
)
|
||||||
|
|
||||||
|
ids = word / "commentsIds.xml"
|
||||||
|
if not ids.exists():
|
||||||
|
shutil.copy(TEMPLATE_DIR / "commentsIds.xml", ids)
|
||||||
|
_append_xml(
|
||||||
|
ids,
|
||||||
|
"w16cid:commentsIds",
|
||||||
|
f'<w16cid:commentId w16cid:paraId="{para_id}" w16cid:durableId="{durable_id}"/>',
|
||||||
|
)
|
||||||
|
|
||||||
|
extensible = word / "commentsExtensible.xml"
|
||||||
|
if not extensible.exists():
|
||||||
|
shutil.copy(TEMPLATE_DIR / "commentsExtensible.xml", extensible)
|
||||||
|
_append_xml(
|
||||||
|
extensible,
|
||||||
|
"w16cex:commentsExtensible",
|
||||||
|
f'<w16cex:commentExtensible w16cex:durableId="{durable_id}" w16cex:dateUtc="{ts}"/>',
|
||||||
|
)
|
||||||
|
|
||||||
|
action = "reply" if parent_id is not None else "comment"
|
||||||
|
return para_id, f"Added {action} {comment_id} (para_id={para_id})"
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
p = argparse.ArgumentParser(description="Add comments to DOCX documents")
|
||||||
|
p.add_argument("unpacked_dir", help="Unpacked DOCX directory")
|
||||||
|
p.add_argument("comment_id", type=int, help="Comment ID (must be unique)")
|
||||||
|
p.add_argument("text", help="Comment text")
|
||||||
|
p.add_argument("--author", default="Claude", help="Author name")
|
||||||
|
p.add_argument("--initials", default="C", help="Author initials")
|
||||||
|
p.add_argument("--parent", type=int, help="Parent comment ID (for replies)")
|
||||||
|
args = p.parse_args()
|
||||||
|
|
||||||
|
para_id, msg = add_comment(
|
||||||
|
args.unpacked_dir,
|
||||||
|
args.comment_id,
|
||||||
|
args.text,
|
||||||
|
args.author,
|
||||||
|
args.initials,
|
||||||
|
args.parent,
|
||||||
|
)
|
||||||
|
print(msg)
|
||||||
|
if "Error" in msg:
|
||||||
|
sys.exit(1)
|
||||||
|
cid = args.comment_id
|
||||||
|
if args.parent is not None:
|
||||||
|
print(REPLY_MARKER_TEMPLATE.format(pid=args.parent, cid=cid))
|
||||||
|
else:
|
||||||
|
print(COMMENT_MARKER_TEMPLATE.format(cid=cid))
|
||||||
@ -0,0 +1,199 @@
|
|||||||
|
"""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)
|
||||||
@ -0,0 +1,197 @@
|
|||||||
|
"""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."
|
||||||
|
)
|
||||||
159
mateclaw-server/src/main/resources/skills/docx/scripts/office/pack.py
Executable file
159
mateclaw-server/src/main/resources/skills/docx/scripts/office/pack.py
Executable file
@ -0,0 +1,159 @@
|
|||||||
|
"""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)
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,146 @@
|
|||||||
|
<?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>
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,11 @@
|
|||||||
|
<?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>
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,23 @@
|
|||||||
|
<?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>
|
||||||
@ -0,0 +1,185 @@
|
|||||||
|
<?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/spreadsheetDrawing"
|
||||||
|
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
||||||
|
targetNamespace="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"
|
||||||
|
elementFormDefault="qualified">
|
||||||
|
<xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/main"
|
||||||
|
schemaLocation="dml-main.xsd"/>
|
||||||
|
<xsd:import schemaLocation="shared-relationshipReference.xsd"
|
||||||
|
namespace="http://schemas.openxmlformats.org/officeDocument/2006/relationships"/>
|
||||||
|
<xsd:element name="from" type="CT_Marker"/>
|
||||||
|
<xsd:element name="to" type="CT_Marker"/>
|
||||||
|
<xsd:complexType name="CT_AnchorClientData">
|
||||||
|
<xsd:attribute name="fLocksWithSheet" type="xsd:boolean" use="optional" default="true"/>
|
||||||
|
<xsd:attribute name="fPrintsWithSheet" type="xsd:boolean" use="optional" default="true"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<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_GraphicalObjectFrameNonVisual">
|
||||||
|
<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_GraphicalObjectFrame">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="nvGraphicFramePr" type="CT_GraphicalObjectFrameNonVisual" 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_GraphicalObjectFrame"/>
|
||||||
|
<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_GraphicalObjectFrame"/>
|
||||||
|
<xsd:element name="cxnSp" type="CT_Connector"/>
|
||||||
|
<xsd:element name="pic" type="CT_Picture"/>
|
||||||
|
<xsd:element name="contentPart" type="CT_Rel"/>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:group>
|
||||||
|
<xsd:complexType name="CT_Rel">
|
||||||
|
<xsd:attribute ref="r:id" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_ColID">
|
||||||
|
<xsd:restriction base="xsd:int">
|
||||||
|
<xsd:minInclusive value="0"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_RowID">
|
||||||
|
<xsd:restriction base="xsd:int">
|
||||||
|
<xsd:minInclusive value="0"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_Marker">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="col" type="ST_ColID"/>
|
||||||
|
<xsd:element name="colOff" type="a:ST_Coordinate"/>
|
||||||
|
<xsd:element name="row" type="ST_RowID"/>
|
||||||
|
<xsd:element name="rowOff" type="a:ST_Coordinate"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_EditAs">
|
||||||
|
<xsd:restriction base="xsd:token">
|
||||||
|
<xsd:enumeration value="twoCell"/>
|
||||||
|
<xsd:enumeration value="oneCell"/>
|
||||||
|
<xsd:enumeration value="absolute"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_TwoCellAnchor">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="from" type="CT_Marker"/>
|
||||||
|
<xsd:element name="to" type="CT_Marker"/>
|
||||||
|
<xsd:group ref="EG_ObjectChoices"/>
|
||||||
|
<xsd:element name="clientData" type="CT_AnchorClientData" minOccurs="1" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="editAs" type="ST_EditAs" use="optional" default="twoCell"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_OneCellAnchor">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="from" type="CT_Marker"/>
|
||||||
|
<xsd:element name="ext" type="a:CT_PositiveSize2D"/>
|
||||||
|
<xsd:group ref="EG_ObjectChoices"/>
|
||||||
|
<xsd:element name="clientData" type="CT_AnchorClientData" minOccurs="1" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_AbsoluteAnchor">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="pos" type="a:CT_Point2D"/>
|
||||||
|
<xsd:element name="ext" type="a:CT_PositiveSize2D"/>
|
||||||
|
<xsd:group ref="EG_ObjectChoices"/>
|
||||||
|
<xsd:element name="clientData" type="CT_AnchorClientData" minOccurs="1" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:group name="EG_Anchor">
|
||||||
|
<xsd:choice>
|
||||||
|
<xsd:element name="twoCellAnchor" type="CT_TwoCellAnchor"/>
|
||||||
|
<xsd:element name="oneCellAnchor" type="CT_OneCellAnchor"/>
|
||||||
|
<xsd:element name="absoluteAnchor" type="CT_AbsoluteAnchor"/>
|
||||||
|
</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:element name="wsDr" type="CT_Drawing"/>
|
||||||
|
</xsd:schema>
|
||||||
@ -0,0 +1,287 @@
|
|||||||
|
<?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:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
|
||||||
|
xmlns:dpct="http://schemas.openxmlformats.org/drawingml/2006/picture"
|
||||||
|
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
||||||
|
xmlns="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"
|
||||||
|
targetNamespace="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"
|
||||||
|
elementFormDefault="qualified">
|
||||||
|
<xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/main"
|
||||||
|
schemaLocation="dml-main.xsd"/>
|
||||||
|
<xsd:import schemaLocation="wml.xsd"
|
||||||
|
namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main"/>
|
||||||
|
<xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/picture"
|
||||||
|
schemaLocation="dml-picture.xsd"/>
|
||||||
|
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
||||||
|
schemaLocation="shared-relationshipReference.xsd"/>
|
||||||
|
<xsd:complexType name="CT_EffectExtent">
|
||||||
|
<xsd:attribute name="l" type="a:ST_Coordinate" use="required"/>
|
||||||
|
<xsd:attribute name="t" type="a:ST_Coordinate" use="required"/>
|
||||||
|
<xsd:attribute name="r" type="a:ST_Coordinate" use="required"/>
|
||||||
|
<xsd:attribute name="b" type="a:ST_Coordinate" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_WrapDistance">
|
||||||
|
<xsd:restriction base="xsd:unsignedInt"/>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_Inline">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="extent" type="a:CT_PositiveSize2D"/>
|
||||||
|
<xsd:element name="effectExtent" type="CT_EffectExtent" minOccurs="0"/>
|
||||||
|
<xsd:element name="docPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
|
||||||
|
<xsd:element name="cNvGraphicFramePr" type="a:CT_NonVisualGraphicFrameProperties"
|
||||||
|
minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xsd:element ref="a:graphic" minOccurs="1" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="distT" type="ST_WrapDistance" use="optional"/>
|
||||||
|
<xsd:attribute name="distB" type="ST_WrapDistance" use="optional"/>
|
||||||
|
<xsd:attribute name="distL" type="ST_WrapDistance" use="optional"/>
|
||||||
|
<xsd:attribute name="distR" type="ST_WrapDistance" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_WrapText">
|
||||||
|
<xsd:restriction base="xsd:token">
|
||||||
|
<xsd:enumeration value="bothSides"/>
|
||||||
|
<xsd:enumeration value="left"/>
|
||||||
|
<xsd:enumeration value="right"/>
|
||||||
|
<xsd:enumeration value="largest"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_WrapPath">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="start" type="a:CT_Point2D" minOccurs="1" maxOccurs="1"/>
|
||||||
|
<xsd:element name="lineTo" type="a:CT_Point2D" minOccurs="2" maxOccurs="unbounded"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="edited" type="xsd:boolean" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_WrapNone"/>
|
||||||
|
<xsd:complexType name="CT_WrapSquare">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="effectExtent" type="CT_EffectExtent" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="wrapText" type="ST_WrapText" use="required"/>
|
||||||
|
<xsd:attribute name="distT" type="ST_WrapDistance" use="optional"/>
|
||||||
|
<xsd:attribute name="distB" type="ST_WrapDistance" use="optional"/>
|
||||||
|
<xsd:attribute name="distL" type="ST_WrapDistance" use="optional"/>
|
||||||
|
<xsd:attribute name="distR" type="ST_WrapDistance" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_WrapTight">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="wrapPolygon" type="CT_WrapPath" minOccurs="1" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="wrapText" type="ST_WrapText" use="required"/>
|
||||||
|
<xsd:attribute name="distL" type="ST_WrapDistance" use="optional"/>
|
||||||
|
<xsd:attribute name="distR" type="ST_WrapDistance" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_WrapThrough">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="wrapPolygon" type="CT_WrapPath" minOccurs="1" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="wrapText" type="ST_WrapText" use="required"/>
|
||||||
|
<xsd:attribute name="distL" type="ST_WrapDistance" use="optional"/>
|
||||||
|
<xsd:attribute name="distR" type="ST_WrapDistance" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_WrapTopBottom">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="effectExtent" type="CT_EffectExtent" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="distT" type="ST_WrapDistance" use="optional"/>
|
||||||
|
<xsd:attribute name="distB" type="ST_WrapDistance" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:group name="EG_WrapType">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:choice minOccurs="1" maxOccurs="1">
|
||||||
|
<xsd:element name="wrapNone" type="CT_WrapNone" minOccurs="1" maxOccurs="1"/>
|
||||||
|
<xsd:element name="wrapSquare" type="CT_WrapSquare" minOccurs="1" maxOccurs="1"/>
|
||||||
|
<xsd:element name="wrapTight" type="CT_WrapTight" minOccurs="1" maxOccurs="1"/>
|
||||||
|
<xsd:element name="wrapThrough" type="CT_WrapThrough" minOccurs="1" maxOccurs="1"/>
|
||||||
|
<xsd:element name="wrapTopAndBottom" type="CT_WrapTopBottom" minOccurs="1" maxOccurs="1"/>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:group>
|
||||||
|
<xsd:simpleType name="ST_PositionOffset">
|
||||||
|
<xsd:restriction base="xsd:int"/>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_AlignH">
|
||||||
|
<xsd:restriction base="xsd:token">
|
||||||
|
<xsd:enumeration value="left"/>
|
||||||
|
<xsd:enumeration value="right"/>
|
||||||
|
<xsd:enumeration value="center"/>
|
||||||
|
<xsd:enumeration value="inside"/>
|
||||||
|
<xsd:enumeration value="outside"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_RelFromH">
|
||||||
|
<xsd:restriction base="xsd:token">
|
||||||
|
<xsd:enumeration value="margin"/>
|
||||||
|
<xsd:enumeration value="page"/>
|
||||||
|
<xsd:enumeration value="column"/>
|
||||||
|
<xsd:enumeration value="character"/>
|
||||||
|
<xsd:enumeration value="leftMargin"/>
|
||||||
|
<xsd:enumeration value="rightMargin"/>
|
||||||
|
<xsd:enumeration value="insideMargin"/>
|
||||||
|
<xsd:enumeration value="outsideMargin"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_PosH">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:choice minOccurs="1" maxOccurs="1">
|
||||||
|
<xsd:element name="align" type="ST_AlignH" minOccurs="1" maxOccurs="1"/>
|
||||||
|
<xsd:element name="posOffset" type="ST_PositionOffset" minOccurs="1" maxOccurs="1"/>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="relativeFrom" type="ST_RelFromH" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_AlignV">
|
||||||
|
<xsd:restriction base="xsd:token">
|
||||||
|
<xsd:enumeration value="top"/>
|
||||||
|
<xsd:enumeration value="bottom"/>
|
||||||
|
<xsd:enumeration value="center"/>
|
||||||
|
<xsd:enumeration value="inside"/>
|
||||||
|
<xsd:enumeration value="outside"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_RelFromV">
|
||||||
|
<xsd:restriction base="xsd:token">
|
||||||
|
<xsd:enumeration value="margin"/>
|
||||||
|
<xsd:enumeration value="page"/>
|
||||||
|
<xsd:enumeration value="paragraph"/>
|
||||||
|
<xsd:enumeration value="line"/>
|
||||||
|
<xsd:enumeration value="topMargin"/>
|
||||||
|
<xsd:enumeration value="bottomMargin"/>
|
||||||
|
<xsd:enumeration value="insideMargin"/>
|
||||||
|
<xsd:enumeration value="outsideMargin"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_PosV">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:choice minOccurs="1" maxOccurs="1">
|
||||||
|
<xsd:element name="align" type="ST_AlignV" minOccurs="1" maxOccurs="1"/>
|
||||||
|
<xsd:element name="posOffset" type="ST_PositionOffset" minOccurs="1" maxOccurs="1"/>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="relativeFrom" type="ST_RelFromV" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Anchor">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="simplePos" type="a:CT_Point2D"/>
|
||||||
|
<xsd:element name="positionH" type="CT_PosH"/>
|
||||||
|
<xsd:element name="positionV" type="CT_PosV"/>
|
||||||
|
<xsd:element name="extent" type="a:CT_PositiveSize2D"/>
|
||||||
|
<xsd:element name="effectExtent" type="CT_EffectExtent" minOccurs="0"/>
|
||||||
|
<xsd:group ref="EG_WrapType"/>
|
||||||
|
<xsd:element name="docPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
|
||||||
|
<xsd:element name="cNvGraphicFramePr" type="a:CT_NonVisualGraphicFrameProperties"
|
||||||
|
minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xsd:element ref="a:graphic" minOccurs="1" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="distT" type="ST_WrapDistance" use="optional"/>
|
||||||
|
<xsd:attribute name="distB" type="ST_WrapDistance" use="optional"/>
|
||||||
|
<xsd:attribute name="distL" type="ST_WrapDistance" use="optional"/>
|
||||||
|
<xsd:attribute name="distR" type="ST_WrapDistance" use="optional"/>
|
||||||
|
<xsd:attribute name="simplePos" type="xsd:boolean"/>
|
||||||
|
<xsd:attribute name="relativeHeight" type="xsd:unsignedInt" use="required"/>
|
||||||
|
<xsd:attribute name="behindDoc" type="xsd:boolean" use="required"/>
|
||||||
|
<xsd:attribute name="locked" type="xsd:boolean" use="required"/>
|
||||||
|
<xsd:attribute name="layoutInCell" type="xsd:boolean" use="required"/>
|
||||||
|
<xsd:attribute name="hidden" type="xsd:boolean" use="optional"/>
|
||||||
|
<xsd:attribute name="allowOverlap" type="xsd:boolean" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_TxbxContent">
|
||||||
|
<xsd:group ref="w:EG_BlockLevelElts" minOccurs="1" maxOccurs="unbounded"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_TextboxInfo">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="txbxContent" type="CT_TxbxContent" minOccurs="1" maxOccurs="1"/>
|
||||||
|
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="id" type="xsd:unsignedShort" use="optional" default="0"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_LinkedTextboxInformation">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="id" type="xsd:unsignedShort" use="required"/>
|
||||||
|
<xsd:attribute name="seq" type="xsd:unsignedShort" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_WordprocessingShape">
|
||||||
|
<xsd:sequence minOccurs="1" maxOccurs="1">
|
||||||
|
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xsd:choice minOccurs="1" maxOccurs="1">
|
||||||
|
<xsd:element name="cNvSpPr" type="a:CT_NonVisualDrawingShapeProps" minOccurs="1"
|
||||||
|
maxOccurs="1"/>
|
||||||
|
<xsd:element name="cNvCnPr" type="a:CT_NonVisualConnectorProperties" minOccurs="1"
|
||||||
|
maxOccurs="1"/>
|
||||||
|
</xsd:choice>
|
||||||
|
<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="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xsd:choice minOccurs="0" maxOccurs="1">
|
||||||
|
<xsd:element name="txbx" type="CT_TextboxInfo" minOccurs="1" maxOccurs="1"/>
|
||||||
|
<xsd:element name="linkedTxbx" type="CT_LinkedTextboxInformation" minOccurs="1"
|
||||||
|
maxOccurs="1"/>
|
||||||
|
</xsd:choice>
|
||||||
|
<xsd:element name="bodyPr" type="a:CT_TextBodyProperties" minOccurs="1" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="normalEastAsianFlow" type="xsd:boolean" use="optional" default="false"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_GraphicFrame">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
|
||||||
|
<xsd:element name="cNvFrPr" type="a:CT_NonVisualGraphicFrameProperties" 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:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_WordprocessingContentPartNonVisual">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xsd:element name="cNvContentPartPr" type="a:CT_NonVisualContentPartProperties" minOccurs="0" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_WordprocessingContentPart">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="nvContentPartPr" type="CT_WordprocessingContentPartNonVisual" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xsd:element name="xfrm" type="a:CT_Transform2D" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="bwMode" type="a:ST_BlackWhiteMode" use="optional"/>
|
||||||
|
<xsd:attribute ref="r:id" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_WordprocessingGroup">
|
||||||
|
<xsd:sequence minOccurs="1" maxOccurs="1">
|
||||||
|
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xsd:element name="cNvGrpSpPr" type="a:CT_NonVisualGroupDrawingShapeProps" minOccurs="1"
|
||||||
|
maxOccurs="1"/>
|
||||||
|
<xsd:element name="grpSpPr" type="a:CT_GroupShapeProperties" minOccurs="1" maxOccurs="1"/>
|
||||||
|
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||||
|
<xsd:element ref="wsp"/>
|
||||||
|
<xsd:element name="grpSp" type="CT_WordprocessingGroup"/>
|
||||||
|
<xsd:element name="graphicFrame" type="CT_GraphicFrame"/>
|
||||||
|
<xsd:element ref="dpct:pic"/>
|
||||||
|
<xsd:element name="contentPart" type="CT_WordprocessingContentPart"/>
|
||||||
|
</xsd:choice>
|
||||||
|
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_WordprocessingCanvas">
|
||||||
|
<xsd:sequence minOccurs="1" maxOccurs="1">
|
||||||
|
<xsd:element name="bg" type="a:CT_BackgroundFormatting" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xsd:element name="whole" type="a:CT_WholeE2oFormatting" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||||
|
<xsd:element ref="wsp"/>
|
||||||
|
<xsd:element ref="dpct:pic"/>
|
||||||
|
<xsd:element name="contentPart" type="CT_WordprocessingContentPart"/>
|
||||||
|
<xsd:element ref="wgp"/>
|
||||||
|
<xsd:element name="graphicFrame" type="CT_GraphicFrame"/>
|
||||||
|
</xsd:choice>
|
||||||
|
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:element name="wpc" type="CT_WordprocessingCanvas"/>
|
||||||
|
<xsd:element name="wgp" type="CT_WordprocessingGroup"/>
|
||||||
|
<xsd:element name="wsp" type="CT_WordprocessingShape"/>
|
||||||
|
<xsd:element name="inline" type="CT_Inline"/>
|
||||||
|
<xsd:element name="anchor" type="CT_Anchor"/>
|
||||||
|
</xsd:schema>
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,28 @@
|
|||||||
|
<?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>
|
||||||
@ -0,0 +1,144 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||||
|
xmlns="http://schemas.openxmlformats.org/officeDocument/2006/bibliography"
|
||||||
|
xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||||
|
targetNamespace="http://schemas.openxmlformats.org/officeDocument/2006/bibliography"
|
||||||
|
elementFormDefault="qualified">
|
||||||
|
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||||
|
schemaLocation="shared-commonSimpleTypes.xsd"/>
|
||||||
|
<xsd:simpleType name="ST_SourceType">
|
||||||
|
<xsd:restriction base="s:ST_String">
|
||||||
|
<xsd:enumeration value="ArticleInAPeriodical"/>
|
||||||
|
<xsd:enumeration value="Book"/>
|
||||||
|
<xsd:enumeration value="BookSection"/>
|
||||||
|
<xsd:enumeration value="JournalArticle"/>
|
||||||
|
<xsd:enumeration value="ConferenceProceedings"/>
|
||||||
|
<xsd:enumeration value="Report"/>
|
||||||
|
<xsd:enumeration value="SoundRecording"/>
|
||||||
|
<xsd:enumeration value="Performance"/>
|
||||||
|
<xsd:enumeration value="Art"/>
|
||||||
|
<xsd:enumeration value="DocumentFromInternetSite"/>
|
||||||
|
<xsd:enumeration value="InternetSite"/>
|
||||||
|
<xsd:enumeration value="Film"/>
|
||||||
|
<xsd:enumeration value="Interview"/>
|
||||||
|
<xsd:enumeration value="Patent"/>
|
||||||
|
<xsd:enumeration value="ElectronicSource"/>
|
||||||
|
<xsd:enumeration value="Case"/>
|
||||||
|
<xsd:enumeration value="Misc"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_NameListType">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="Person" type="CT_PersonType" minOccurs="1" maxOccurs="unbounded"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_PersonType">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="Last" type="s:ST_String" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
<xsd:element name="First" type="s:ST_String" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
<xsd:element name="Middle" type="s:ST_String" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_NameType">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="NameList" type="CT_NameListType" minOccurs="1" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_NameOrCorporateType">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:choice minOccurs="0" maxOccurs="1">
|
||||||
|
<xsd:element name="NameList" type="CT_NameListType" minOccurs="1" maxOccurs="1"/>
|
||||||
|
<xsd:element name="Corporate" minOccurs="1" maxOccurs="1" type="s:ST_String"/>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_AuthorType">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||||
|
<xsd:element name="Artist" type="CT_NameType"/>
|
||||||
|
<xsd:element name="Author" type="CT_NameOrCorporateType"/>
|
||||||
|
<xsd:element name="BookAuthor" type="CT_NameType"/>
|
||||||
|
<xsd:element name="Compiler" type="CT_NameType"/>
|
||||||
|
<xsd:element name="Composer" type="CT_NameType"/>
|
||||||
|
<xsd:element name="Conductor" type="CT_NameType"/>
|
||||||
|
<xsd:element name="Counsel" type="CT_NameType"/>
|
||||||
|
<xsd:element name="Director" type="CT_NameType"/>
|
||||||
|
<xsd:element name="Editor" type="CT_NameType"/>
|
||||||
|
<xsd:element name="Interviewee" type="CT_NameType"/>
|
||||||
|
<xsd:element name="Interviewer" type="CT_NameType"/>
|
||||||
|
<xsd:element name="Inventor" type="CT_NameType"/>
|
||||||
|
<xsd:element name="Performer" type="CT_NameOrCorporateType"/>
|
||||||
|
<xsd:element name="ProducerName" type="CT_NameType"/>
|
||||||
|
<xsd:element name="Translator" type="CT_NameType"/>
|
||||||
|
<xsd:element name="Writer" type="CT_NameType"/>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_SourceType">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||||
|
<xsd:element name="AbbreviatedCaseNumber" type="s:ST_String"/>
|
||||||
|
<xsd:element name="AlbumTitle" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Author" type="CT_AuthorType"/>
|
||||||
|
<xsd:element name="BookTitle" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Broadcaster" type="s:ST_String"/>
|
||||||
|
<xsd:element name="BroadcastTitle" type="s:ST_String"/>
|
||||||
|
<xsd:element name="CaseNumber" type="s:ST_String"/>
|
||||||
|
<xsd:element name="ChapterNumber" type="s:ST_String"/>
|
||||||
|
<xsd:element name="City" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Comments" type="s:ST_String"/>
|
||||||
|
<xsd:element name="ConferenceName" type="s:ST_String"/>
|
||||||
|
<xsd:element name="CountryRegion" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Court" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Day" type="s:ST_String"/>
|
||||||
|
<xsd:element name="DayAccessed" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Department" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Distributor" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Edition" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Guid" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Institution" type="s:ST_String"/>
|
||||||
|
<xsd:element name="InternetSiteTitle" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Issue" type="s:ST_String"/>
|
||||||
|
<xsd:element name="JournalName" type="s:ST_String"/>
|
||||||
|
<xsd:element name="LCID" type="s:ST_Lang"/>
|
||||||
|
<xsd:element name="Medium" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Month" type="s:ST_String"/>
|
||||||
|
<xsd:element name="MonthAccessed" type="s:ST_String"/>
|
||||||
|
<xsd:element name="NumberVolumes" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Pages" type="s:ST_String"/>
|
||||||
|
<xsd:element name="PatentNumber" type="s:ST_String"/>
|
||||||
|
<xsd:element name="PeriodicalTitle" type="s:ST_String"/>
|
||||||
|
<xsd:element name="ProductionCompany" type="s:ST_String"/>
|
||||||
|
<xsd:element name="PublicationTitle" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Publisher" type="s:ST_String"/>
|
||||||
|
<xsd:element name="RecordingNumber" type="s:ST_String"/>
|
||||||
|
<xsd:element name="RefOrder" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Reporter" type="s:ST_String"/>
|
||||||
|
<xsd:element name="SourceType" type="ST_SourceType"/>
|
||||||
|
<xsd:element name="ShortTitle" type="s:ST_String"/>
|
||||||
|
<xsd:element name="StandardNumber" type="s:ST_String"/>
|
||||||
|
<xsd:element name="StateProvince" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Station" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Tag" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Theater" type="s:ST_String"/>
|
||||||
|
<xsd:element name="ThesisType" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Title" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Type" type="s:ST_String"/>
|
||||||
|
<xsd:element name="URL" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Version" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Volume" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Year" type="s:ST_String"/>
|
||||||
|
<xsd:element name="YearAccessed" type="s:ST_String"/>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:element name="Sources" type="CT_Sources"/>
|
||||||
|
<xsd:complexType name="CT_Sources">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="Source" type="CT_SourceType" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="SelectedStyle" type="s:ST_String"/>
|
||||||
|
<xsd:attribute name="StyleName" type="s:ST_String"/>
|
||||||
|
<xsd:attribute name="URI" type="s:ST_String"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:schema>
|
||||||
@ -0,0 +1,174 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||||
|
xmlns="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||||
|
targetNamespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||||
|
elementFormDefault="qualified">
|
||||||
|
<xsd:simpleType name="ST_Lang">
|
||||||
|
<xsd:restriction base="xsd:string"/>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_HexColorRGB">
|
||||||
|
<xsd:restriction base="xsd:hexBinary">
|
||||||
|
<xsd:length value="3" fixed="true"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_Panose">
|
||||||
|
<xsd:restriction base="xsd:hexBinary">
|
||||||
|
<xsd:length value="10"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_CalendarType">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="gregorian"/>
|
||||||
|
<xsd:enumeration value="gregorianUs"/>
|
||||||
|
<xsd:enumeration value="gregorianMeFrench"/>
|
||||||
|
<xsd:enumeration value="gregorianArabic"/>
|
||||||
|
<xsd:enumeration value="hijri"/>
|
||||||
|
<xsd:enumeration value="hebrew"/>
|
||||||
|
<xsd:enumeration value="taiwan"/>
|
||||||
|
<xsd:enumeration value="japan"/>
|
||||||
|
<xsd:enumeration value="thai"/>
|
||||||
|
<xsd:enumeration value="korea"/>
|
||||||
|
<xsd:enumeration value="saka"/>
|
||||||
|
<xsd:enumeration value="gregorianXlitEnglish"/>
|
||||||
|
<xsd:enumeration value="gregorianXlitFrench"/>
|
||||||
|
<xsd:enumeration value="none"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_AlgClass">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="hash"/>
|
||||||
|
<xsd:enumeration value="custom"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_CryptProv">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="rsaAES"/>
|
||||||
|
<xsd:enumeration value="rsaFull"/>
|
||||||
|
<xsd:enumeration value="custom"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_AlgType">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="typeAny"/>
|
||||||
|
<xsd:enumeration value="custom"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_ColorType">
|
||||||
|
<xsd:restriction base="xsd:string"/>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_Guid">
|
||||||
|
<xsd:restriction base="xsd:token">
|
||||||
|
<xsd:pattern value="\{[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}\}"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_OnOff">
|
||||||
|
<xsd:union memberTypes="xsd:boolean ST_OnOff1"/>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_OnOff1">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="on"/>
|
||||||
|
<xsd:enumeration value="off"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_String">
|
||||||
|
<xsd:restriction base="xsd:string"/>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_XmlName">
|
||||||
|
<xsd:restriction base="xsd:NCName">
|
||||||
|
<xsd:minLength value="1"/>
|
||||||
|
<xsd:maxLength value="255"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_TrueFalse">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="t"/>
|
||||||
|
<xsd:enumeration value="f"/>
|
||||||
|
<xsd:enumeration value="true"/>
|
||||||
|
<xsd:enumeration value="false"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_TrueFalseBlank">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="t"/>
|
||||||
|
<xsd:enumeration value="f"/>
|
||||||
|
<xsd:enumeration value="true"/>
|
||||||
|
<xsd:enumeration value="false"/>
|
||||||
|
<xsd:enumeration value=""/>
|
||||||
|
<xsd:enumeration value="True"/>
|
||||||
|
<xsd:enumeration value="False"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_UnsignedDecimalNumber">
|
||||||
|
<xsd:restriction base="xsd:decimal">
|
||||||
|
<xsd:minInclusive value="0"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_TwipsMeasure">
|
||||||
|
<xsd:union memberTypes="ST_UnsignedDecimalNumber ST_PositiveUniversalMeasure"/>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_VerticalAlignRun">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="baseline"/>
|
||||||
|
<xsd:enumeration value="superscript"/>
|
||||||
|
<xsd:enumeration value="subscript"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_Xstring">
|
||||||
|
<xsd:restriction base="xsd:string"/>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_XAlign">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="left"/>
|
||||||
|
<xsd:enumeration value="center"/>
|
||||||
|
<xsd:enumeration value="right"/>
|
||||||
|
<xsd:enumeration value="inside"/>
|
||||||
|
<xsd:enumeration value="outside"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_YAlign">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="inline"/>
|
||||||
|
<xsd:enumeration value="top"/>
|
||||||
|
<xsd:enumeration value="center"/>
|
||||||
|
<xsd:enumeration value="bottom"/>
|
||||||
|
<xsd:enumeration value="inside"/>
|
||||||
|
<xsd:enumeration value="outside"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_ConformanceClass">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="strict"/>
|
||||||
|
<xsd:enumeration value="transitional"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_UniversalMeasure">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:pattern value="-?[0-9]+(\.[0-9]+)?(mm|cm|in|pt|pc|pi)"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_PositiveUniversalMeasure">
|
||||||
|
<xsd:restriction base="ST_UniversalMeasure">
|
||||||
|
<xsd:pattern value="[0-9]+(\.[0-9]+)?(mm|cm|in|pt|pc|pi)"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_Percentage">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:pattern value="-?[0-9]+(\.[0-9]+)?%"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_FixedPercentage">
|
||||||
|
<xsd:restriction base="ST_Percentage">
|
||||||
|
<xsd:pattern value="-?((100)|([0-9][0-9]?))(\.[0-9][0-9]?)?%"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_PositivePercentage">
|
||||||
|
<xsd:restriction base="ST_Percentage">
|
||||||
|
<xsd:pattern value="[0-9]+(\.[0-9]+)?%"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_PositiveFixedPercentage">
|
||||||
|
<xsd:restriction base="ST_Percentage">
|
||||||
|
<xsd:pattern value="((100)|([0-9][0-9]?))(\.[0-9][0-9]?)?%"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
</xsd:schema>
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
<?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>
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
<?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>
|
||||||
@ -0,0 +1,59 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||||
|
xmlns="http://schemas.openxmlformats.org/officeDocument/2006/custom-properties"
|
||||||
|
xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"
|
||||||
|
xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||||
|
targetNamespace="http://schemas.openxmlformats.org/officeDocument/2006/custom-properties"
|
||||||
|
blockDefault="#all" elementFormDefault="qualified">
|
||||||
|
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"
|
||||||
|
schemaLocation="shared-documentPropertiesVariantTypes.xsd"/>
|
||||||
|
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||||
|
schemaLocation="shared-commonSimpleTypes.xsd"/>
|
||||||
|
<xsd:element name="Properties" type="CT_Properties"/>
|
||||||
|
<xsd:complexType name="CT_Properties">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="property" minOccurs="0" maxOccurs="unbounded" type="CT_Property"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Property">
|
||||||
|
<xsd:choice minOccurs="1" maxOccurs="1">
|
||||||
|
<xsd:element ref="vt:vector"/>
|
||||||
|
<xsd:element ref="vt:array"/>
|
||||||
|
<xsd:element ref="vt:blob"/>
|
||||||
|
<xsd:element ref="vt:oblob"/>
|
||||||
|
<xsd:element ref="vt:empty"/>
|
||||||
|
<xsd:element ref="vt:null"/>
|
||||||
|
<xsd:element ref="vt:i1"/>
|
||||||
|
<xsd:element ref="vt:i2"/>
|
||||||
|
<xsd:element ref="vt:i4"/>
|
||||||
|
<xsd:element ref="vt:i8"/>
|
||||||
|
<xsd:element ref="vt:int"/>
|
||||||
|
<xsd:element ref="vt:ui1"/>
|
||||||
|
<xsd:element ref="vt:ui2"/>
|
||||||
|
<xsd:element ref="vt:ui4"/>
|
||||||
|
<xsd:element ref="vt:ui8"/>
|
||||||
|
<xsd:element ref="vt:uint"/>
|
||||||
|
<xsd:element ref="vt:r4"/>
|
||||||
|
<xsd:element ref="vt:r8"/>
|
||||||
|
<xsd:element ref="vt:decimal"/>
|
||||||
|
<xsd:element ref="vt:lpstr"/>
|
||||||
|
<xsd:element ref="vt:lpwstr"/>
|
||||||
|
<xsd:element ref="vt:bstr"/>
|
||||||
|
<xsd:element ref="vt:date"/>
|
||||||
|
<xsd:element ref="vt:filetime"/>
|
||||||
|
<xsd:element ref="vt:bool"/>
|
||||||
|
<xsd:element ref="vt:cy"/>
|
||||||
|
<xsd:element ref="vt:error"/>
|
||||||
|
<xsd:element ref="vt:stream"/>
|
||||||
|
<xsd:element ref="vt:ostream"/>
|
||||||
|
<xsd:element ref="vt:storage"/>
|
||||||
|
<xsd:element ref="vt:ostorage"/>
|
||||||
|
<xsd:element ref="vt:vstream"/>
|
||||||
|
<xsd:element ref="vt:clsid"/>
|
||||||
|
</xsd:choice>
|
||||||
|
<xsd:attribute name="fmtid" use="required" type="s:ST_Guid"/>
|
||||||
|
<xsd:attribute name="pid" use="required" type="xsd:int"/>
|
||||||
|
<xsd:attribute name="name" use="optional" type="xsd:string"/>
|
||||||
|
<xsd:attribute name="linkTarget" use="optional" type="xsd:string"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:schema>
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||||
|
xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties"
|
||||||
|
xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"
|
||||||
|
targetNamespace="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties"
|
||||||
|
elementFormDefault="qualified" blockDefault="#all">
|
||||||
|
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"
|
||||||
|
schemaLocation="shared-documentPropertiesVariantTypes.xsd"/>
|
||||||
|
<xsd:element name="Properties" type="CT_Properties"/>
|
||||||
|
<xsd:complexType name="CT_Properties">
|
||||||
|
<xsd:all>
|
||||||
|
<xsd:element name="Template" minOccurs="0" maxOccurs="1" type="xsd:string"/>
|
||||||
|
<xsd:element name="Manager" minOccurs="0" maxOccurs="1" type="xsd:string"/>
|
||||||
|
<xsd:element name="Company" minOccurs="0" maxOccurs="1" type="xsd:string"/>
|
||||||
|
<xsd:element name="Pages" minOccurs="0" maxOccurs="1" type="xsd:int"/>
|
||||||
|
<xsd:element name="Words" minOccurs="0" maxOccurs="1" type="xsd:int"/>
|
||||||
|
<xsd:element name="Characters" minOccurs="0" maxOccurs="1" type="xsd:int"/>
|
||||||
|
<xsd:element name="PresentationFormat" minOccurs="0" maxOccurs="1" type="xsd:string"/>
|
||||||
|
<xsd:element name="Lines" minOccurs="0" maxOccurs="1" type="xsd:int"/>
|
||||||
|
<xsd:element name="Paragraphs" minOccurs="0" maxOccurs="1" type="xsd:int"/>
|
||||||
|
<xsd:element name="Slides" minOccurs="0" maxOccurs="1" type="xsd:int"/>
|
||||||
|
<xsd:element name="Notes" minOccurs="0" maxOccurs="1" type="xsd:int"/>
|
||||||
|
<xsd:element name="TotalTime" minOccurs="0" maxOccurs="1" type="xsd:int"/>
|
||||||
|
<xsd:element name="HiddenSlides" minOccurs="0" maxOccurs="1" type="xsd:int"/>
|
||||||
|
<xsd:element name="MMClips" minOccurs="0" maxOccurs="1" type="xsd:int"/>
|
||||||
|
<xsd:element name="ScaleCrop" minOccurs="0" maxOccurs="1" type="xsd:boolean"/>
|
||||||
|
<xsd:element name="HeadingPairs" minOccurs="0" maxOccurs="1" type="CT_VectorVariant"/>
|
||||||
|
<xsd:element name="TitlesOfParts" minOccurs="0" maxOccurs="1" type="CT_VectorLpstr"/>
|
||||||
|
<xsd:element name="LinksUpToDate" minOccurs="0" maxOccurs="1" type="xsd:boolean"/>
|
||||||
|
<xsd:element name="CharactersWithSpaces" minOccurs="0" maxOccurs="1" type="xsd:int"/>
|
||||||
|
<xsd:element name="SharedDoc" minOccurs="0" maxOccurs="1" type="xsd:boolean"/>
|
||||||
|
<xsd:element name="HyperlinkBase" minOccurs="0" maxOccurs="1" type="xsd:string"/>
|
||||||
|
<xsd:element name="HLinks" minOccurs="0" maxOccurs="1" type="CT_VectorVariant"/>
|
||||||
|
<xsd:element name="HyperlinksChanged" minOccurs="0" maxOccurs="1" type="xsd:boolean"/>
|
||||||
|
<xsd:element name="DigSig" minOccurs="0" maxOccurs="1" type="CT_DigSigBlob"/>
|
||||||
|
<xsd:element name="Application" minOccurs="0" maxOccurs="1" type="xsd:string"/>
|
||||||
|
<xsd:element name="AppVersion" minOccurs="0" maxOccurs="1" type="xsd:string"/>
|
||||||
|
<xsd:element name="DocSecurity" minOccurs="0" maxOccurs="1" type="xsd:int"/>
|
||||||
|
</xsd:all>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_VectorVariant">
|
||||||
|
<xsd:sequence minOccurs="1" maxOccurs="1">
|
||||||
|
<xsd:element ref="vt:vector"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_VectorLpstr">
|
||||||
|
<xsd:sequence minOccurs="1" maxOccurs="1">
|
||||||
|
<xsd:element ref="vt:vector"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_DigSigBlob">
|
||||||
|
<xsd:sequence minOccurs="1" maxOccurs="1">
|
||||||
|
<xsd:element ref="vt:blob"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:schema>
|
||||||
@ -0,0 +1,195 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||||
|
xmlns="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"
|
||||||
|
xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||||
|
targetNamespace="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"
|
||||||
|
blockDefault="#all" elementFormDefault="qualified">
|
||||||
|
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||||
|
schemaLocation="shared-commonSimpleTypes.xsd"/>
|
||||||
|
<xsd:simpleType name="ST_VectorBaseType">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="variant"/>
|
||||||
|
<xsd:enumeration value="i1"/>
|
||||||
|
<xsd:enumeration value="i2"/>
|
||||||
|
<xsd:enumeration value="i4"/>
|
||||||
|
<xsd:enumeration value="i8"/>
|
||||||
|
<xsd:enumeration value="ui1"/>
|
||||||
|
<xsd:enumeration value="ui2"/>
|
||||||
|
<xsd:enumeration value="ui4"/>
|
||||||
|
<xsd:enumeration value="ui8"/>
|
||||||
|
<xsd:enumeration value="r4"/>
|
||||||
|
<xsd:enumeration value="r8"/>
|
||||||
|
<xsd:enumeration value="lpstr"/>
|
||||||
|
<xsd:enumeration value="lpwstr"/>
|
||||||
|
<xsd:enumeration value="bstr"/>
|
||||||
|
<xsd:enumeration value="date"/>
|
||||||
|
<xsd:enumeration value="filetime"/>
|
||||||
|
<xsd:enumeration value="bool"/>
|
||||||
|
<xsd:enumeration value="cy"/>
|
||||||
|
<xsd:enumeration value="error"/>
|
||||||
|
<xsd:enumeration value="clsid"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_ArrayBaseType">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="variant"/>
|
||||||
|
<xsd:enumeration value="i1"/>
|
||||||
|
<xsd:enumeration value="i2"/>
|
||||||
|
<xsd:enumeration value="i4"/>
|
||||||
|
<xsd:enumeration value="int"/>
|
||||||
|
<xsd:enumeration value="ui1"/>
|
||||||
|
<xsd:enumeration value="ui2"/>
|
||||||
|
<xsd:enumeration value="ui4"/>
|
||||||
|
<xsd:enumeration value="uint"/>
|
||||||
|
<xsd:enumeration value="r4"/>
|
||||||
|
<xsd:enumeration value="r8"/>
|
||||||
|
<xsd:enumeration value="decimal"/>
|
||||||
|
<xsd:enumeration value="bstr"/>
|
||||||
|
<xsd:enumeration value="date"/>
|
||||||
|
<xsd:enumeration value="bool"/>
|
||||||
|
<xsd:enumeration value="cy"/>
|
||||||
|
<xsd:enumeration value="error"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_Cy">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:pattern value="\s*[0-9]*\.[0-9]{4}\s*"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_Error">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:pattern value="\s*0x[0-9A-Za-z]{8}\s*"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_Empty"/>
|
||||||
|
<xsd:complexType name="CT_Null"/>
|
||||||
|
<xsd:complexType name="CT_Vector">
|
||||||
|
<xsd:choice minOccurs="1" maxOccurs="unbounded">
|
||||||
|
<xsd:element ref="variant"/>
|
||||||
|
<xsd:element ref="i1"/>
|
||||||
|
<xsd:element ref="i2"/>
|
||||||
|
<xsd:element ref="i4"/>
|
||||||
|
<xsd:element ref="i8"/>
|
||||||
|
<xsd:element ref="ui1"/>
|
||||||
|
<xsd:element ref="ui2"/>
|
||||||
|
<xsd:element ref="ui4"/>
|
||||||
|
<xsd:element ref="ui8"/>
|
||||||
|
<xsd:element ref="r4"/>
|
||||||
|
<xsd:element ref="r8"/>
|
||||||
|
<xsd:element ref="lpstr"/>
|
||||||
|
<xsd:element ref="lpwstr"/>
|
||||||
|
<xsd:element ref="bstr"/>
|
||||||
|
<xsd:element ref="date"/>
|
||||||
|
<xsd:element ref="filetime"/>
|
||||||
|
<xsd:element ref="bool"/>
|
||||||
|
<xsd:element ref="cy"/>
|
||||||
|
<xsd:element ref="error"/>
|
||||||
|
<xsd:element ref="clsid"/>
|
||||||
|
</xsd:choice>
|
||||||
|
<xsd:attribute name="baseType" type="ST_VectorBaseType" use="required"/>
|
||||||
|
<xsd:attribute name="size" type="xsd:unsignedInt" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Array">
|
||||||
|
<xsd:choice minOccurs="1" maxOccurs="unbounded">
|
||||||
|
<xsd:element ref="variant"/>
|
||||||
|
<xsd:element ref="i1"/>
|
||||||
|
<xsd:element ref="i2"/>
|
||||||
|
<xsd:element ref="i4"/>
|
||||||
|
<xsd:element ref="int"/>
|
||||||
|
<xsd:element ref="ui1"/>
|
||||||
|
<xsd:element ref="ui2"/>
|
||||||
|
<xsd:element ref="ui4"/>
|
||||||
|
<xsd:element ref="uint"/>
|
||||||
|
<xsd:element ref="r4"/>
|
||||||
|
<xsd:element ref="r8"/>
|
||||||
|
<xsd:element ref="decimal"/>
|
||||||
|
<xsd:element ref="bstr"/>
|
||||||
|
<xsd:element ref="date"/>
|
||||||
|
<xsd:element ref="bool"/>
|
||||||
|
<xsd:element ref="error"/>
|
||||||
|
<xsd:element ref="cy"/>
|
||||||
|
</xsd:choice>
|
||||||
|
<xsd:attribute name="lBounds" type="xsd:int" use="required"/>
|
||||||
|
<xsd:attribute name="uBounds" type="xsd:int" use="required"/>
|
||||||
|
<xsd:attribute name="baseType" type="ST_ArrayBaseType" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Variant">
|
||||||
|
<xsd:choice minOccurs="1" maxOccurs="1">
|
||||||
|
<xsd:element ref="variant"/>
|
||||||
|
<xsd:element ref="vector"/>
|
||||||
|
<xsd:element ref="array"/>
|
||||||
|
<xsd:element ref="blob"/>
|
||||||
|
<xsd:element ref="oblob"/>
|
||||||
|
<xsd:element ref="empty"/>
|
||||||
|
<xsd:element ref="null"/>
|
||||||
|
<xsd:element ref="i1"/>
|
||||||
|
<xsd:element ref="i2"/>
|
||||||
|
<xsd:element ref="i4"/>
|
||||||
|
<xsd:element ref="i8"/>
|
||||||
|
<xsd:element ref="int"/>
|
||||||
|
<xsd:element ref="ui1"/>
|
||||||
|
<xsd:element ref="ui2"/>
|
||||||
|
<xsd:element ref="ui4"/>
|
||||||
|
<xsd:element ref="ui8"/>
|
||||||
|
<xsd:element ref="uint"/>
|
||||||
|
<xsd:element ref="r4"/>
|
||||||
|
<xsd:element ref="r8"/>
|
||||||
|
<xsd:element ref="decimal"/>
|
||||||
|
<xsd:element ref="lpstr"/>
|
||||||
|
<xsd:element ref="lpwstr"/>
|
||||||
|
<xsd:element ref="bstr"/>
|
||||||
|
<xsd:element ref="date"/>
|
||||||
|
<xsd:element ref="filetime"/>
|
||||||
|
<xsd:element ref="bool"/>
|
||||||
|
<xsd:element ref="cy"/>
|
||||||
|
<xsd:element ref="error"/>
|
||||||
|
<xsd:element ref="stream"/>
|
||||||
|
<xsd:element ref="ostream"/>
|
||||||
|
<xsd:element ref="storage"/>
|
||||||
|
<xsd:element ref="ostorage"/>
|
||||||
|
<xsd:element ref="vstream"/>
|
||||||
|
<xsd:element ref="clsid"/>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Vstream">
|
||||||
|
<xsd:simpleContent>
|
||||||
|
<xsd:extension base="xsd:base64Binary">
|
||||||
|
<xsd:attribute name="version" type="s:ST_Guid"/>
|
||||||
|
</xsd:extension>
|
||||||
|
</xsd:simpleContent>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:element name="variant" type="CT_Variant"/>
|
||||||
|
<xsd:element name="vector" type="CT_Vector"/>
|
||||||
|
<xsd:element name="array" type="CT_Array"/>
|
||||||
|
<xsd:element name="blob" type="xsd:base64Binary"/>
|
||||||
|
<xsd:element name="oblob" type="xsd:base64Binary"/>
|
||||||
|
<xsd:element name="empty" type="CT_Empty"/>
|
||||||
|
<xsd:element name="null" type="CT_Null"/>
|
||||||
|
<xsd:element name="i1" type="xsd:byte"/>
|
||||||
|
<xsd:element name="i2" type="xsd:short"/>
|
||||||
|
<xsd:element name="i4" type="xsd:int"/>
|
||||||
|
<xsd:element name="i8" type="xsd:long"/>
|
||||||
|
<xsd:element name="int" type="xsd:int"/>
|
||||||
|
<xsd:element name="ui1" type="xsd:unsignedByte"/>
|
||||||
|
<xsd:element name="ui2" type="xsd:unsignedShort"/>
|
||||||
|
<xsd:element name="ui4" type="xsd:unsignedInt"/>
|
||||||
|
<xsd:element name="ui8" type="xsd:unsignedLong"/>
|
||||||
|
<xsd:element name="uint" type="xsd:unsignedInt"/>
|
||||||
|
<xsd:element name="r4" type="xsd:float"/>
|
||||||
|
<xsd:element name="r8" type="xsd:double"/>
|
||||||
|
<xsd:element name="decimal" type="xsd:decimal"/>
|
||||||
|
<xsd:element name="lpstr" type="xsd:string"/>
|
||||||
|
<xsd:element name="lpwstr" type="xsd:string"/>
|
||||||
|
<xsd:element name="bstr" type="xsd:string"/>
|
||||||
|
<xsd:element name="date" type="xsd:dateTime"/>
|
||||||
|
<xsd:element name="filetime" type="xsd:dateTime"/>
|
||||||
|
<xsd:element name="bool" type="xsd:boolean"/>
|
||||||
|
<xsd:element name="cy" type="ST_Cy"/>
|
||||||
|
<xsd:element name="error" type="ST_Error"/>
|
||||||
|
<xsd:element name="stream" type="xsd:base64Binary"/>
|
||||||
|
<xsd:element name="ostream" type="xsd:base64Binary"/>
|
||||||
|
<xsd:element name="storage" type="xsd:base64Binary"/>
|
||||||
|
<xsd:element name="ostorage" type="xsd:base64Binary"/>
|
||||||
|
<xsd:element name="vstream" type="CT_Vstream"/>
|
||||||
|
<xsd:element name="clsid" type="s:ST_Guid"/>
|
||||||
|
</xsd:schema>
|
||||||
@ -0,0 +1,582 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||||
|
xmlns="http://schemas.openxmlformats.org/officeDocument/2006/math"
|
||||||
|
xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math"
|
||||||
|
xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
|
||||||
|
xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||||
|
elementFormDefault="qualified" attributeFormDefault="qualified" blockDefault="#all"
|
||||||
|
targetNamespace="http://schemas.openxmlformats.org/officeDocument/2006/math">
|
||||||
|
<xsd:import namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
|
||||||
|
schemaLocation="wml.xsd"/>
|
||||||
|
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||||
|
schemaLocation="shared-commonSimpleTypes.xsd"/>
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="xml.xsd"/>
|
||||||
|
<xsd:simpleType name="ST_Integer255">
|
||||||
|
<xsd:restriction base="xsd:integer">
|
||||||
|
<xsd:minInclusive value="1"/>
|
||||||
|
<xsd:maxInclusive value="255"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_Integer255">
|
||||||
|
<xsd:attribute name="val" type="ST_Integer255" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_Integer2">
|
||||||
|
<xsd:restriction base="xsd:integer">
|
||||||
|
<xsd:minInclusive value="-2"/>
|
||||||
|
<xsd:maxInclusive value="2"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_Integer2">
|
||||||
|
<xsd:attribute name="val" type="ST_Integer2" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_SpacingRule">
|
||||||
|
<xsd:restriction base="xsd:integer">
|
||||||
|
<xsd:minInclusive value="0"/>
|
||||||
|
<xsd:maxInclusive value="4"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_SpacingRule">
|
||||||
|
<xsd:attribute name="val" type="ST_SpacingRule" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_UnSignedInteger">
|
||||||
|
<xsd:restriction base="xsd:unsignedInt"/>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_UnSignedInteger">
|
||||||
|
<xsd:attribute name="val" type="ST_UnSignedInteger" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_Char">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:maxLength value="1"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_Char">
|
||||||
|
<xsd:attribute name="val" type="ST_Char" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_OnOff">
|
||||||
|
<xsd:attribute name="val" type="s:ST_OnOff"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_String">
|
||||||
|
<xsd:attribute name="val" type="s:ST_String"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_XAlign">
|
||||||
|
<xsd:attribute name="val" type="s:ST_XAlign" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_YAlign">
|
||||||
|
<xsd:attribute name="val" type="s:ST_YAlign" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_Shp">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="centered"/>
|
||||||
|
<xsd:enumeration value="match"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_Shp">
|
||||||
|
<xsd:attribute name="val" type="ST_Shp" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_FType">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="bar"/>
|
||||||
|
<xsd:enumeration value="skw"/>
|
||||||
|
<xsd:enumeration value="lin"/>
|
||||||
|
<xsd:enumeration value="noBar"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_FType">
|
||||||
|
<xsd:attribute name="val" type="ST_FType" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_LimLoc">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="undOvr"/>
|
||||||
|
<xsd:enumeration value="subSup"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_LimLoc">
|
||||||
|
<xsd:attribute name="val" type="ST_LimLoc" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_TopBot">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="top"/>
|
||||||
|
<xsd:enumeration value="bot"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_TopBot">
|
||||||
|
<xsd:attribute name="val" type="ST_TopBot" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_Script">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="roman"/>
|
||||||
|
<xsd:enumeration value="script"/>
|
||||||
|
<xsd:enumeration value="fraktur"/>
|
||||||
|
<xsd:enumeration value="double-struck"/>
|
||||||
|
<xsd:enumeration value="sans-serif"/>
|
||||||
|
<xsd:enumeration value="monospace"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_Script">
|
||||||
|
<xsd:attribute name="val" type="ST_Script"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_Style">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="p"/>
|
||||||
|
<xsd:enumeration value="b"/>
|
||||||
|
<xsd:enumeration value="i"/>
|
||||||
|
<xsd:enumeration value="bi"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_Style">
|
||||||
|
<xsd:attribute name="val" type="ST_Style"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_ManualBreak">
|
||||||
|
<xsd:attribute name="alnAt" type="ST_Integer255"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:group name="EG_ScriptStyle">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="scr" minOccurs="0" type="CT_Script"/>
|
||||||
|
<xsd:element name="sty" minOccurs="0" type="CT_Style"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:group>
|
||||||
|
<xsd:complexType name="CT_RPR">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="lit" minOccurs="0" type="CT_OnOff"/>
|
||||||
|
<xsd:choice>
|
||||||
|
<xsd:element name="nor" minOccurs="0" type="CT_OnOff"/>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:group ref="EG_ScriptStyle"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:choice>
|
||||||
|
<xsd:element name="brk" minOccurs="0" type="CT_ManualBreak"/>
|
||||||
|
<xsd:element name="aln" minOccurs="0" type="CT_OnOff"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Text">
|
||||||
|
<xsd:simpleContent>
|
||||||
|
<xsd:extension base="s:ST_String">
|
||||||
|
<xsd:attribute ref="xml:space" use="optional"/>
|
||||||
|
</xsd:extension>
|
||||||
|
</xsd:simpleContent>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_R">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="rPr" type="CT_RPR" minOccurs="0"/>
|
||||||
|
<xsd:group ref="w:EG_RPr" minOccurs="0"/>
|
||||||
|
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||||
|
<xsd:group ref="w:EG_RunInnerContent"/>
|
||||||
|
<xsd:element name="t" type="CT_Text" minOccurs="0"/>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_CtrlPr">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:group ref="w:EG_RPrMath" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_AccPr">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="chr" type="CT_Char" minOccurs="0"/>
|
||||||
|
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Acc">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="accPr" type="CT_AccPr" minOccurs="0"/>
|
||||||
|
<xsd:element name="e" type="CT_OMathArg"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_BarPr">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="pos" type="CT_TopBot" minOccurs="0"/>
|
||||||
|
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Bar">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="barPr" type="CT_BarPr" minOccurs="0"/>
|
||||||
|
<xsd:element name="e" type="CT_OMathArg"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_BoxPr">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="opEmu" type="CT_OnOff" minOccurs="0"/>
|
||||||
|
<xsd:element name="noBreak" type="CT_OnOff" minOccurs="0"/>
|
||||||
|
<xsd:element name="diff" type="CT_OnOff" minOccurs="0"/>
|
||||||
|
<xsd:element name="brk" type="CT_ManualBreak" minOccurs="0"/>
|
||||||
|
<xsd:element name="aln" type="CT_OnOff" minOccurs="0"/>
|
||||||
|
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Box">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="boxPr" type="CT_BoxPr" minOccurs="0"/>
|
||||||
|
<xsd:element name="e" type="CT_OMathArg"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_BorderBoxPr">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="hideTop" type="CT_OnOff" minOccurs="0"/>
|
||||||
|
<xsd:element name="hideBot" type="CT_OnOff" minOccurs="0"/>
|
||||||
|
<xsd:element name="hideLeft" type="CT_OnOff" minOccurs="0"/>
|
||||||
|
<xsd:element name="hideRight" type="CT_OnOff" minOccurs="0"/>
|
||||||
|
<xsd:element name="strikeH" type="CT_OnOff" minOccurs="0"/>
|
||||||
|
<xsd:element name="strikeV" type="CT_OnOff" minOccurs="0"/>
|
||||||
|
<xsd:element name="strikeBLTR" type="CT_OnOff" minOccurs="0"/>
|
||||||
|
<xsd:element name="strikeTLBR" type="CT_OnOff" minOccurs="0"/>
|
||||||
|
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_BorderBox">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="borderBoxPr" type="CT_BorderBoxPr" minOccurs="0"/>
|
||||||
|
<xsd:element name="e" type="CT_OMathArg"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_DPr">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="begChr" type="CT_Char" minOccurs="0"/>
|
||||||
|
<xsd:element name="sepChr" type="CT_Char" minOccurs="0"/>
|
||||||
|
<xsd:element name="endChr" type="CT_Char" minOccurs="0"/>
|
||||||
|
<xsd:element name="grow" type="CT_OnOff" minOccurs="0"/>
|
||||||
|
<xsd:element name="shp" type="CT_Shp" minOccurs="0"/>
|
||||||
|
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_D">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="dPr" type="CT_DPr" minOccurs="0"/>
|
||||||
|
<xsd:element name="e" type="CT_OMathArg" maxOccurs="unbounded"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_EqArrPr">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="baseJc" type="CT_YAlign" minOccurs="0"/>
|
||||||
|
<xsd:element name="maxDist" type="CT_OnOff" minOccurs="0"/>
|
||||||
|
<xsd:element name="objDist" type="CT_OnOff" minOccurs="0"/>
|
||||||
|
<xsd:element name="rSpRule" type="CT_SpacingRule" minOccurs="0"/>
|
||||||
|
<xsd:element name="rSp" type="CT_UnSignedInteger" minOccurs="0"/>
|
||||||
|
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_EqArr">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="eqArrPr" type="CT_EqArrPr" minOccurs="0"/>
|
||||||
|
<xsd:element name="e" type="CT_OMathArg" maxOccurs="unbounded"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_FPr">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="type" type="CT_FType" minOccurs="0"/>
|
||||||
|
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_F">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="fPr" type="CT_FPr" minOccurs="0"/>
|
||||||
|
<xsd:element name="num" type="CT_OMathArg"/>
|
||||||
|
<xsd:element name="den" type="CT_OMathArg"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_FuncPr">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Func">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="funcPr" type="CT_FuncPr" minOccurs="0"/>
|
||||||
|
<xsd:element name="fName" type="CT_OMathArg"/>
|
||||||
|
<xsd:element name="e" type="CT_OMathArg"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_GroupChrPr">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="chr" type="CT_Char" minOccurs="0"/>
|
||||||
|
<xsd:element name="pos" type="CT_TopBot" minOccurs="0"/>
|
||||||
|
<xsd:element name="vertJc" type="CT_TopBot" minOccurs="0"/>
|
||||||
|
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_GroupChr">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="groupChrPr" type="CT_GroupChrPr" minOccurs="0"/>
|
||||||
|
<xsd:element name="e" type="CT_OMathArg"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_LimLowPr">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_LimLow">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="limLowPr" type="CT_LimLowPr" minOccurs="0"/>
|
||||||
|
<xsd:element name="e" type="CT_OMathArg"/>
|
||||||
|
<xsd:element name="lim" type="CT_OMathArg"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_LimUppPr">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_LimUpp">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="limUppPr" type="CT_LimUppPr" minOccurs="0"/>
|
||||||
|
<xsd:element name="e" type="CT_OMathArg"/>
|
||||||
|
<xsd:element name="lim" type="CT_OMathArg"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_MCPr">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="count" type="CT_Integer255" minOccurs="0"/>
|
||||||
|
<xsd:element name="mcJc" type="CT_XAlign" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_MC">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="mcPr" type="CT_MCPr" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_MCS">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="mc" type="CT_MC" maxOccurs="unbounded"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_MPr">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="baseJc" type="CT_YAlign" minOccurs="0"/>
|
||||||
|
<xsd:element name="plcHide" type="CT_OnOff" minOccurs="0"/>
|
||||||
|
<xsd:element name="rSpRule" type="CT_SpacingRule" minOccurs="0"/>
|
||||||
|
<xsd:element name="cGpRule" type="CT_SpacingRule" minOccurs="0"/>
|
||||||
|
<xsd:element name="rSp" type="CT_UnSignedInteger" minOccurs="0"/>
|
||||||
|
<xsd:element name="cSp" type="CT_UnSignedInteger" minOccurs="0"/>
|
||||||
|
<xsd:element name="cGp" type="CT_UnSignedInteger" minOccurs="0"/>
|
||||||
|
<xsd:element name="mcs" type="CT_MCS" minOccurs="0"/>
|
||||||
|
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_MR">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="e" type="CT_OMathArg" maxOccurs="unbounded"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_M">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="mPr" type="CT_MPr" minOccurs="0"/>
|
||||||
|
<xsd:element name="mr" type="CT_MR" maxOccurs="unbounded"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_NaryPr">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="chr" type="CT_Char" minOccurs="0"/>
|
||||||
|
<xsd:element name="limLoc" type="CT_LimLoc" minOccurs="0"/>
|
||||||
|
<xsd:element name="grow" type="CT_OnOff" minOccurs="0"/>
|
||||||
|
<xsd:element name="subHide" type="CT_OnOff" minOccurs="0"/>
|
||||||
|
<xsd:element name="supHide" type="CT_OnOff" minOccurs="0"/>
|
||||||
|
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Nary">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="naryPr" type="CT_NaryPr" minOccurs="0"/>
|
||||||
|
<xsd:element name="sub" type="CT_OMathArg"/>
|
||||||
|
<xsd:element name="sup" type="CT_OMathArg"/>
|
||||||
|
<xsd:element name="e" type="CT_OMathArg"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_PhantPr">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="show" type="CT_OnOff" minOccurs="0"/>
|
||||||
|
<xsd:element name="zeroWid" type="CT_OnOff" minOccurs="0"/>
|
||||||
|
<xsd:element name="zeroAsc" type="CT_OnOff" minOccurs="0"/>
|
||||||
|
<xsd:element name="zeroDesc" type="CT_OnOff" minOccurs="0"/>
|
||||||
|
<xsd:element name="transp" type="CT_OnOff" minOccurs="0"/>
|
||||||
|
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Phant">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="phantPr" type="CT_PhantPr" minOccurs="0"/>
|
||||||
|
<xsd:element name="e" type="CT_OMathArg"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_RadPr">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="degHide" type="CT_OnOff" minOccurs="0"/>
|
||||||
|
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Rad">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="radPr" type="CT_RadPr" minOccurs="0"/>
|
||||||
|
<xsd:element name="deg" type="CT_OMathArg"/>
|
||||||
|
<xsd:element name="e" type="CT_OMathArg"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_SPrePr">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_SPre">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="sPrePr" type="CT_SPrePr" minOccurs="0"/>
|
||||||
|
<xsd:element name="sub" type="CT_OMathArg"/>
|
||||||
|
<xsd:element name="sup" type="CT_OMathArg"/>
|
||||||
|
<xsd:element name="e" type="CT_OMathArg"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_SSubPr">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_SSub">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="sSubPr" type="CT_SSubPr" minOccurs="0"/>
|
||||||
|
<xsd:element name="e" type="CT_OMathArg"/>
|
||||||
|
<xsd:element name="sub" type="CT_OMathArg"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_SSubSupPr">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="alnScr" type="CT_OnOff" minOccurs="0"/>
|
||||||
|
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_SSubSup">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="sSubSupPr" type="CT_SSubSupPr" minOccurs="0"/>
|
||||||
|
<xsd:element name="e" type="CT_OMathArg"/>
|
||||||
|
<xsd:element name="sub" type="CT_OMathArg"/>
|
||||||
|
<xsd:element name="sup" type="CT_OMathArg"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_SSupPr">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_SSup">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="sSupPr" type="CT_SSupPr" minOccurs="0"/>
|
||||||
|
<xsd:element name="e" type="CT_OMathArg"/>
|
||||||
|
<xsd:element name="sup" type="CT_OMathArg"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:group name="EG_OMathMathElements">
|
||||||
|
<xsd:choice>
|
||||||
|
<xsd:element name="acc" type="CT_Acc"/>
|
||||||
|
<xsd:element name="bar" type="CT_Bar"/>
|
||||||
|
<xsd:element name="box" type="CT_Box"/>
|
||||||
|
<xsd:element name="borderBox" type="CT_BorderBox"/>
|
||||||
|
<xsd:element name="d" type="CT_D"/>
|
||||||
|
<xsd:element name="eqArr" type="CT_EqArr"/>
|
||||||
|
<xsd:element name="f" type="CT_F"/>
|
||||||
|
<xsd:element name="func" type="CT_Func"/>
|
||||||
|
<xsd:element name="groupChr" type="CT_GroupChr"/>
|
||||||
|
<xsd:element name="limLow" type="CT_LimLow"/>
|
||||||
|
<xsd:element name="limUpp" type="CT_LimUpp"/>
|
||||||
|
<xsd:element name="m" type="CT_M"/>
|
||||||
|
<xsd:element name="nary" type="CT_Nary"/>
|
||||||
|
<xsd:element name="phant" type="CT_Phant"/>
|
||||||
|
<xsd:element name="rad" type="CT_Rad"/>
|
||||||
|
<xsd:element name="sPre" type="CT_SPre"/>
|
||||||
|
<xsd:element name="sSub" type="CT_SSub"/>
|
||||||
|
<xsd:element name="sSubSup" type="CT_SSubSup"/>
|
||||||
|
<xsd:element name="sSup" type="CT_SSup"/>
|
||||||
|
<xsd:element name="r" type="CT_R"/>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:group>
|
||||||
|
<xsd:group name="EG_OMathElements">
|
||||||
|
<xsd:choice>
|
||||||
|
<xsd:group ref="EG_OMathMathElements"/>
|
||||||
|
<xsd:group ref="w:EG_PContentMath"/>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:group>
|
||||||
|
<xsd:complexType name="CT_OMathArgPr">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="argSz" type="CT_Integer2" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_OMathArg">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="argPr" type="CT_OMathArgPr" minOccurs="0"/>
|
||||||
|
<xsd:group ref="EG_OMathElements" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
<xsd:element name="ctrlPr" type="CT_CtrlPr" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_Jc">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="left"/>
|
||||||
|
<xsd:enumeration value="right"/>
|
||||||
|
<xsd:enumeration value="center"/>
|
||||||
|
<xsd:enumeration value="centerGroup"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_OMathJc">
|
||||||
|
<xsd:attribute name="val" type="ST_Jc"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_OMathParaPr">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="jc" type="CT_OMathJc" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_TwipsMeasure">
|
||||||
|
<xsd:attribute name="val" type="s:ST_TwipsMeasure" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_BreakBin">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="before"/>
|
||||||
|
<xsd:enumeration value="after"/>
|
||||||
|
<xsd:enumeration value="repeat"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_BreakBin">
|
||||||
|
<xsd:attribute name="val" type="ST_BreakBin"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_BreakBinSub">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="--"/>
|
||||||
|
<xsd:enumeration value="-+"/>
|
||||||
|
<xsd:enumeration value="+-"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_BreakBinSub">
|
||||||
|
<xsd:attribute name="val" type="ST_BreakBinSub"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_MathPr">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="mathFont" type="CT_String" minOccurs="0"/>
|
||||||
|
<xsd:element name="brkBin" type="CT_BreakBin" minOccurs="0"/>
|
||||||
|
<xsd:element name="brkBinSub" type="CT_BreakBinSub" minOccurs="0"/>
|
||||||
|
<xsd:element name="smallFrac" type="CT_OnOff" minOccurs="0"/>
|
||||||
|
<xsd:element name="dispDef" type="CT_OnOff" minOccurs="0"/>
|
||||||
|
<xsd:element name="lMargin" type="CT_TwipsMeasure" minOccurs="0"/>
|
||||||
|
<xsd:element name="rMargin" type="CT_TwipsMeasure" minOccurs="0"/>
|
||||||
|
<xsd:element name="defJc" type="CT_OMathJc" minOccurs="0"/>
|
||||||
|
<xsd:element name="preSp" type="CT_TwipsMeasure" minOccurs="0"/>
|
||||||
|
<xsd:element name="postSp" type="CT_TwipsMeasure" minOccurs="0"/>
|
||||||
|
<xsd:element name="interSp" type="CT_TwipsMeasure" minOccurs="0"/>
|
||||||
|
<xsd:element name="intraSp" type="CT_TwipsMeasure" minOccurs="0"/>
|
||||||
|
<xsd:choice minOccurs="0">
|
||||||
|
<xsd:element name="wrapIndent" type="CT_TwipsMeasure"/>
|
||||||
|
<xsd:element name="wrapRight" type="CT_OnOff"/>
|
||||||
|
</xsd:choice>
|
||||||
|
<xsd:element name="intLim" type="CT_LimLoc" minOccurs="0"/>
|
||||||
|
<xsd:element name="naryLim" type="CT_LimLoc" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:element name="mathPr" type="CT_MathPr"/>
|
||||||
|
<xsd:complexType name="CT_OMathPara">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="oMathParaPr" type="CT_OMathParaPr" minOccurs="0"/>
|
||||||
|
<xsd:element name="oMath" type="CT_OMath" maxOccurs="unbounded"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_OMath">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:group ref="EG_OMathElements" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:element name="oMathPara" type="CT_OMathPara"/>
|
||||||
|
<xsd:element name="oMath" type="CT_OMath"/>
|
||||||
|
</xsd:schema>
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||||
|
xmlns="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
||||||
|
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
||||||
|
elementFormDefault="qualified"
|
||||||
|
targetNamespace="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
||||||
|
blockDefault="#all">
|
||||||
|
<xsd:simpleType name="ST_RelationshipId">
|
||||||
|
<xsd:restriction base="xsd:string"/>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:attribute name="id" type="ST_RelationshipId"/>
|
||||||
|
<xsd:attribute name="embed" type="ST_RelationshipId"/>
|
||||||
|
<xsd:attribute name="link" type="ST_RelationshipId"/>
|
||||||
|
<xsd:attribute name="dm" type="ST_RelationshipId" default=""/>
|
||||||
|
<xsd:attribute name="lo" type="ST_RelationshipId" default=""/>
|
||||||
|
<xsd:attribute name="qs" type="ST_RelationshipId" default=""/>
|
||||||
|
<xsd:attribute name="cs" type="ST_RelationshipId" default=""/>
|
||||||
|
<xsd:attribute name="blip" type="ST_RelationshipId" default=""/>
|
||||||
|
<xsd:attribute name="pict" type="ST_RelationshipId"/>
|
||||||
|
<xsd:attribute name="href" type="ST_RelationshipId"/>
|
||||||
|
<xsd:attribute name="topLeft" type="ST_RelationshipId"/>
|
||||||
|
<xsd:attribute name="topRight" type="ST_RelationshipId"/>
|
||||||
|
<xsd:attribute name="bottomLeft" type="ST_RelationshipId"/>
|
||||||
|
<xsd:attribute name="bottomRight" type="ST_RelationshipId"/>
|
||||||
|
</xsd:schema>
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,570 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="urn:schemas-microsoft-com:vml"
|
||||||
|
xmlns:pvml="urn:schemas-microsoft-com:office:powerpoint"
|
||||||
|
xmlns:o="urn:schemas-microsoft-com:office:office"
|
||||||
|
xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
|
||||||
|
xmlns:w10="urn:schemas-microsoft-com:office:word"
|
||||||
|
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
||||||
|
xmlns:x="urn:schemas-microsoft-com:office:excel"
|
||||||
|
xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||||
|
targetNamespace="urn:schemas-microsoft-com:vml" elementFormDefault="qualified"
|
||||||
|
attributeFormDefault="unqualified">
|
||||||
|
<xsd:import namespace="urn:schemas-microsoft-com:office:office"
|
||||||
|
schemaLocation="vml-officeDrawing.xsd"/>
|
||||||
|
<xsd:import namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
|
||||||
|
schemaLocation="wml.xsd"/>
|
||||||
|
<xsd:import namespace="urn:schemas-microsoft-com:office:word"
|
||||||
|
schemaLocation="vml-wordprocessingDrawing.xsd"/>
|
||||||
|
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
||||||
|
schemaLocation="shared-relationshipReference.xsd"/>
|
||||||
|
<xsd:import namespace="urn:schemas-microsoft-com:office:excel"
|
||||||
|
schemaLocation="vml-spreadsheetDrawing.xsd"/>
|
||||||
|
<xsd:import namespace="urn:schemas-microsoft-com:office:powerpoint"
|
||||||
|
schemaLocation="vml-presentationDrawing.xsd"/>
|
||||||
|
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||||
|
schemaLocation="shared-commonSimpleTypes.xsd"/>
|
||||||
|
<xsd:attributeGroup name="AG_Id">
|
||||||
|
<xsd:attribute name="id" type="xsd:string" use="optional"/>
|
||||||
|
</xsd:attributeGroup>
|
||||||
|
<xsd:attributeGroup name="AG_Style">
|
||||||
|
<xsd:attribute name="style" type="xsd:string" use="optional"/>
|
||||||
|
</xsd:attributeGroup>
|
||||||
|
<xsd:attributeGroup name="AG_Type">
|
||||||
|
<xsd:attribute name="type" type="xsd:string" use="optional"/>
|
||||||
|
</xsd:attributeGroup>
|
||||||
|
<xsd:attributeGroup name="AG_Adj">
|
||||||
|
<xsd:attribute name="adj" type="xsd:string" use="optional"/>
|
||||||
|
</xsd:attributeGroup>
|
||||||
|
<xsd:attributeGroup name="AG_Path">
|
||||||
|
<xsd:attribute name="path" type="xsd:string" use="optional"/>
|
||||||
|
</xsd:attributeGroup>
|
||||||
|
<xsd:attributeGroup name="AG_Fill">
|
||||||
|
<xsd:attribute name="filled" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="fillcolor" type="s:ST_ColorType" use="optional"/>
|
||||||
|
</xsd:attributeGroup>
|
||||||
|
<xsd:attributeGroup name="AG_Chromakey">
|
||||||
|
<xsd:attribute name="chromakey" type="s:ST_ColorType" use="optional"/>
|
||||||
|
</xsd:attributeGroup>
|
||||||
|
<xsd:attributeGroup name="AG_Ext">
|
||||||
|
<xsd:attribute name="ext" form="qualified" type="ST_Ext"/>
|
||||||
|
</xsd:attributeGroup>
|
||||||
|
<xsd:attributeGroup name="AG_CoreAttributes">
|
||||||
|
<xsd:attributeGroup ref="AG_Id"/>
|
||||||
|
<xsd:attributeGroup ref="AG_Style"/>
|
||||||
|
<xsd:attribute name="href" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="target" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="class" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="title" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="alt" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="coordsize" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="coordorigin" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="wrapcoords" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="print" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
</xsd:attributeGroup>
|
||||||
|
<xsd:attributeGroup name="AG_ShapeAttributes">
|
||||||
|
<xsd:attributeGroup ref="AG_Chromakey"/>
|
||||||
|
<xsd:attributeGroup ref="AG_Fill"/>
|
||||||
|
<xsd:attribute name="opacity" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="stroked" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="strokecolor" type="s:ST_ColorType" use="optional"/>
|
||||||
|
<xsd:attribute name="strokeweight" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="insetpen" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
</xsd:attributeGroup>
|
||||||
|
<xsd:attributeGroup name="AG_OfficeCoreAttributes">
|
||||||
|
<xsd:attribute ref="o:spid"/>
|
||||||
|
<xsd:attribute ref="o:oned"/>
|
||||||
|
<xsd:attribute ref="o:regroupid"/>
|
||||||
|
<xsd:attribute ref="o:doubleclicknotify"/>
|
||||||
|
<xsd:attribute ref="o:button"/>
|
||||||
|
<xsd:attribute ref="o:userhidden"/>
|
||||||
|
<xsd:attribute ref="o:bullet"/>
|
||||||
|
<xsd:attribute ref="o:hr"/>
|
||||||
|
<xsd:attribute ref="o:hrstd"/>
|
||||||
|
<xsd:attribute ref="o:hrnoshade"/>
|
||||||
|
<xsd:attribute ref="o:hrpct"/>
|
||||||
|
<xsd:attribute ref="o:hralign"/>
|
||||||
|
<xsd:attribute ref="o:allowincell"/>
|
||||||
|
<xsd:attribute ref="o:allowoverlap"/>
|
||||||
|
<xsd:attribute ref="o:userdrawn"/>
|
||||||
|
<xsd:attribute ref="o:bordertopcolor"/>
|
||||||
|
<xsd:attribute ref="o:borderleftcolor"/>
|
||||||
|
<xsd:attribute ref="o:borderbottomcolor"/>
|
||||||
|
<xsd:attribute ref="o:borderrightcolor"/>
|
||||||
|
<xsd:attribute ref="o:dgmlayout"/>
|
||||||
|
<xsd:attribute ref="o:dgmnodekind"/>
|
||||||
|
<xsd:attribute ref="o:dgmlayoutmru"/>
|
||||||
|
<xsd:attribute ref="o:insetmode"/>
|
||||||
|
</xsd:attributeGroup>
|
||||||
|
<xsd:attributeGroup name="AG_OfficeShapeAttributes">
|
||||||
|
<xsd:attribute ref="o:spt"/>
|
||||||
|
<xsd:attribute ref="o:connectortype"/>
|
||||||
|
<xsd:attribute ref="o:bwmode"/>
|
||||||
|
<xsd:attribute ref="o:bwpure"/>
|
||||||
|
<xsd:attribute ref="o:bwnormal"/>
|
||||||
|
<xsd:attribute ref="o:forcedash"/>
|
||||||
|
<xsd:attribute ref="o:oleicon"/>
|
||||||
|
<xsd:attribute ref="o:ole"/>
|
||||||
|
<xsd:attribute ref="o:preferrelative"/>
|
||||||
|
<xsd:attribute ref="o:cliptowrap"/>
|
||||||
|
<xsd:attribute ref="o:clip"/>
|
||||||
|
</xsd:attributeGroup>
|
||||||
|
<xsd:attributeGroup name="AG_AllCoreAttributes">
|
||||||
|
<xsd:attributeGroup ref="AG_CoreAttributes"/>
|
||||||
|
<xsd:attributeGroup ref="AG_OfficeCoreAttributes"/>
|
||||||
|
</xsd:attributeGroup>
|
||||||
|
<xsd:attributeGroup name="AG_AllShapeAttributes">
|
||||||
|
<xsd:attributeGroup ref="AG_ShapeAttributes"/>
|
||||||
|
<xsd:attributeGroup ref="AG_OfficeShapeAttributes"/>
|
||||||
|
</xsd:attributeGroup>
|
||||||
|
<xsd:attributeGroup name="AG_ImageAttributes">
|
||||||
|
<xsd:attribute name="src" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="cropleft" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="croptop" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="cropright" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="cropbottom" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="gain" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="blacklevel" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="gamma" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="grayscale" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="bilevel" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
</xsd:attributeGroup>
|
||||||
|
<xsd:attributeGroup name="AG_StrokeAttributes">
|
||||||
|
<xsd:attribute name="on" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="weight" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="color" type="s:ST_ColorType" use="optional"/>
|
||||||
|
<xsd:attribute name="opacity" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="linestyle" type="ST_StrokeLineStyle" use="optional"/>
|
||||||
|
<xsd:attribute name="miterlimit" type="xsd:decimal" use="optional"/>
|
||||||
|
<xsd:attribute name="joinstyle" type="ST_StrokeJoinStyle" use="optional"/>
|
||||||
|
<xsd:attribute name="endcap" type="ST_StrokeEndCap" use="optional"/>
|
||||||
|
<xsd:attribute name="dashstyle" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="filltype" type="ST_FillType" use="optional"/>
|
||||||
|
<xsd:attribute name="src" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="imageaspect" type="ST_ImageAspect" use="optional"/>
|
||||||
|
<xsd:attribute name="imagesize" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="imagealignshape" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="color2" type="s:ST_ColorType" use="optional"/>
|
||||||
|
<xsd:attribute name="startarrow" type="ST_StrokeArrowType" use="optional"/>
|
||||||
|
<xsd:attribute name="startarrowwidth" type="ST_StrokeArrowWidth" use="optional"/>
|
||||||
|
<xsd:attribute name="startarrowlength" type="ST_StrokeArrowLength" use="optional"/>
|
||||||
|
<xsd:attribute name="endarrow" type="ST_StrokeArrowType" use="optional"/>
|
||||||
|
<xsd:attribute name="endarrowwidth" type="ST_StrokeArrowWidth" use="optional"/>
|
||||||
|
<xsd:attribute name="endarrowlength" type="ST_StrokeArrowLength" use="optional"/>
|
||||||
|
<xsd:attribute ref="o:href"/>
|
||||||
|
<xsd:attribute ref="o:althref"/>
|
||||||
|
<xsd:attribute ref="o:title"/>
|
||||||
|
<xsd:attribute ref="o:forcedash"/>
|
||||||
|
<xsd:attribute ref="r:id" use="optional"/>
|
||||||
|
<xsd:attribute name="insetpen" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute ref="o:relid"/>
|
||||||
|
</xsd:attributeGroup>
|
||||||
|
<xsd:group name="EG_ShapeElements">
|
||||||
|
<xsd:choice>
|
||||||
|
<xsd:element ref="path"/>
|
||||||
|
<xsd:element ref="formulas"/>
|
||||||
|
<xsd:element ref="handles"/>
|
||||||
|
<xsd:element ref="fill"/>
|
||||||
|
<xsd:element ref="stroke"/>
|
||||||
|
<xsd:element ref="shadow"/>
|
||||||
|
<xsd:element ref="textbox"/>
|
||||||
|
<xsd:element ref="textpath"/>
|
||||||
|
<xsd:element ref="imagedata"/>
|
||||||
|
<xsd:element ref="o:skew"/>
|
||||||
|
<xsd:element ref="o:extrusion"/>
|
||||||
|
<xsd:element ref="o:callout"/>
|
||||||
|
<xsd:element ref="o:lock"/>
|
||||||
|
<xsd:element ref="o:clippath"/>
|
||||||
|
<xsd:element ref="o:signatureline"/>
|
||||||
|
<xsd:element ref="w10:wrap"/>
|
||||||
|
<xsd:element ref="w10:anchorlock"/>
|
||||||
|
<xsd:element ref="w10:bordertop"/>
|
||||||
|
<xsd:element ref="w10:borderbottom"/>
|
||||||
|
<xsd:element ref="w10:borderleft"/>
|
||||||
|
<xsd:element ref="w10:borderright"/>
|
||||||
|
<xsd:element ref="x:ClientData" minOccurs="0"/>
|
||||||
|
<xsd:element ref="pvml:textdata" minOccurs="0"/>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:group>
|
||||||
|
<xsd:element name="shape" type="CT_Shape"/>
|
||||||
|
<xsd:element name="shapetype" type="CT_Shapetype"/>
|
||||||
|
<xsd:element name="group" type="CT_Group"/>
|
||||||
|
<xsd:element name="background" type="CT_Background"/>
|
||||||
|
<xsd:complexType name="CT_Shape">
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:group ref="EG_ShapeElements"/>
|
||||||
|
<xsd:element ref="o:ink"/>
|
||||||
|
<xsd:element ref="pvml:iscomment"/>
|
||||||
|
<xsd:element ref="o:equationxml"/>
|
||||||
|
</xsd:choice>
|
||||||
|
<xsd:attributeGroup ref="AG_AllCoreAttributes"/>
|
||||||
|
<xsd:attributeGroup ref="AG_AllShapeAttributes"/>
|
||||||
|
<xsd:attributeGroup ref="AG_Type"/>
|
||||||
|
<xsd:attributeGroup ref="AG_Adj"/>
|
||||||
|
<xsd:attributeGroup ref="AG_Path"/>
|
||||||
|
<xsd:attribute ref="o:gfxdata"/>
|
||||||
|
<xsd:attribute name="equationxml" type="xsd:string" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Shapetype">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:group ref="EG_ShapeElements" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
<xsd:element ref="o:complex" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attributeGroup ref="AG_AllCoreAttributes"/>
|
||||||
|
<xsd:attributeGroup ref="AG_AllShapeAttributes"/>
|
||||||
|
<xsd:attributeGroup ref="AG_Adj"/>
|
||||||
|
<xsd:attributeGroup ref="AG_Path"/>
|
||||||
|
<xsd:attribute ref="o:master"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Group">
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:group ref="EG_ShapeElements"/>
|
||||||
|
<xsd:element ref="group"/>
|
||||||
|
<xsd:element ref="shape"/>
|
||||||
|
<xsd:element ref="shapetype"/>
|
||||||
|
<xsd:element ref="arc"/>
|
||||||
|
<xsd:element ref="curve"/>
|
||||||
|
<xsd:element ref="image"/>
|
||||||
|
<xsd:element ref="line"/>
|
||||||
|
<xsd:element ref="oval"/>
|
||||||
|
<xsd:element ref="polyline"/>
|
||||||
|
<xsd:element ref="rect"/>
|
||||||
|
<xsd:element ref="roundrect"/>
|
||||||
|
<xsd:element ref="o:diagram"/>
|
||||||
|
</xsd:choice>
|
||||||
|
<xsd:attributeGroup ref="AG_AllCoreAttributes"/>
|
||||||
|
<xsd:attributeGroup ref="AG_Fill"/>
|
||||||
|
<xsd:attribute name="editas" type="ST_EditAs" use="optional"/>
|
||||||
|
<xsd:attribute ref="o:tableproperties"/>
|
||||||
|
<xsd:attribute ref="o:tablelimits"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Background">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element ref="fill" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attributeGroup ref="AG_Id"/>
|
||||||
|
<xsd:attributeGroup ref="AG_Fill"/>
|
||||||
|
<xsd:attribute ref="o:bwmode"/>
|
||||||
|
<xsd:attribute ref="o:bwpure"/>
|
||||||
|
<xsd:attribute ref="o:bwnormal"/>
|
||||||
|
<xsd:attribute ref="o:targetscreensize"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:element name="fill" type="CT_Fill"/>
|
||||||
|
<xsd:element name="formulas" type="CT_Formulas"/>
|
||||||
|
<xsd:element name="handles" type="CT_Handles"/>
|
||||||
|
<xsd:element name="imagedata" type="CT_ImageData"/>
|
||||||
|
<xsd:element name="path" type="CT_Path"/>
|
||||||
|
<xsd:element name="textbox" type="CT_Textbox"/>
|
||||||
|
<xsd:element name="shadow" type="CT_Shadow"/>
|
||||||
|
<xsd:element name="stroke" type="CT_Stroke"/>
|
||||||
|
<xsd:element name="textpath" type="CT_TextPath"/>
|
||||||
|
<xsd:complexType name="CT_Fill">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element ref="o:fill" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attributeGroup ref="AG_Id"/>
|
||||||
|
<xsd:attribute name="type" type="ST_FillType" use="optional"/>
|
||||||
|
<xsd:attribute name="on" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="color" type="s:ST_ColorType" use="optional"/>
|
||||||
|
<xsd:attribute name="opacity" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="color2" type="s:ST_ColorType" use="optional"/>
|
||||||
|
<xsd:attribute name="src" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute ref="o:href"/>
|
||||||
|
<xsd:attribute ref="o:althref"/>
|
||||||
|
<xsd:attribute name="size" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="origin" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="position" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="aspect" type="ST_ImageAspect" use="optional"/>
|
||||||
|
<xsd:attribute name="colors" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="angle" type="xsd:decimal" use="optional"/>
|
||||||
|
<xsd:attribute name="alignshape" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="focus" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="focussize" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="focusposition" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="method" type="ST_FillMethod" use="optional"/>
|
||||||
|
<xsd:attribute ref="o:detectmouseclick"/>
|
||||||
|
<xsd:attribute ref="o:title"/>
|
||||||
|
<xsd:attribute ref="o:opacity2"/>
|
||||||
|
<xsd:attribute name="recolor" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="rotate" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute ref="r:id" use="optional"/>
|
||||||
|
<xsd:attribute ref="o:relid" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Formulas">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="f" type="CT_F" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_F">
|
||||||
|
<xsd:attribute name="eqn" type="xsd:string"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Handles">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="h" type="CT_H" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_H">
|
||||||
|
<xsd:attribute name="position" type="xsd:string"/>
|
||||||
|
<xsd:attribute name="polar" type="xsd:string"/>
|
||||||
|
<xsd:attribute name="map" type="xsd:string"/>
|
||||||
|
<xsd:attribute name="invx" type="s:ST_TrueFalse"/>
|
||||||
|
<xsd:attribute name="invy" type="s:ST_TrueFalse"/>
|
||||||
|
<xsd:attribute name="switch" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:attribute name="xrange" type="xsd:string"/>
|
||||||
|
<xsd:attribute name="yrange" type="xsd:string"/>
|
||||||
|
<xsd:attribute name="radiusrange" type="xsd:string"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_ImageData">
|
||||||
|
<xsd:attributeGroup ref="AG_Id"/>
|
||||||
|
<xsd:attributeGroup ref="AG_ImageAttributes"/>
|
||||||
|
<xsd:attributeGroup ref="AG_Chromakey"/>
|
||||||
|
<xsd:attribute name="embosscolor" type="s:ST_ColorType" use="optional"/>
|
||||||
|
<xsd:attribute name="recolortarget" type="s:ST_ColorType"/>
|
||||||
|
<xsd:attribute ref="o:href"/>
|
||||||
|
<xsd:attribute ref="o:althref"/>
|
||||||
|
<xsd:attribute ref="o:title"/>
|
||||||
|
<xsd:attribute ref="o:oleid"/>
|
||||||
|
<xsd:attribute ref="o:detectmouseclick"/>
|
||||||
|
<xsd:attribute ref="o:movie"/>
|
||||||
|
<xsd:attribute ref="o:relid"/>
|
||||||
|
<xsd:attribute ref="r:id"/>
|
||||||
|
<xsd:attribute ref="r:pict"/>
|
||||||
|
<xsd:attribute ref="r:href"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Path">
|
||||||
|
<xsd:attributeGroup ref="AG_Id"/>
|
||||||
|
<xsd:attribute name="v" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="limo" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="textboxrect" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="fillok" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="strokeok" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="shadowok" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="arrowok" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="gradientshapeok" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="textpathok" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="insetpenok" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute ref="o:connecttype"/>
|
||||||
|
<xsd:attribute ref="o:connectlocs"/>
|
||||||
|
<xsd:attribute ref="o:connectangles"/>
|
||||||
|
<xsd:attribute ref="o:extrusionok"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Shadow">
|
||||||
|
<xsd:attributeGroup ref="AG_Id"/>
|
||||||
|
<xsd:attribute name="on" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="type" type="ST_ShadowType" use="optional"/>
|
||||||
|
<xsd:attribute name="obscured" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="color" type="s:ST_ColorType" use="optional"/>
|
||||||
|
<xsd:attribute name="opacity" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="offset" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="color2" type="s:ST_ColorType" use="optional"/>
|
||||||
|
<xsd:attribute name="offset2" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="origin" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="matrix" type="xsd:string" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Stroke">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element ref="o:left" minOccurs="0"/>
|
||||||
|
<xsd:element ref="o:top" minOccurs="0"/>
|
||||||
|
<xsd:element ref="o:right" minOccurs="0"/>
|
||||||
|
<xsd:element ref="o:bottom" minOccurs="0"/>
|
||||||
|
<xsd:element ref="o:column" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attributeGroup ref="AG_Id"/>
|
||||||
|
<xsd:attributeGroup ref="AG_StrokeAttributes"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Textbox">
|
||||||
|
<xsd:choice>
|
||||||
|
<xsd:element ref="w:txbxContent" minOccurs="0"/>
|
||||||
|
<xsd:any namespace="##local" processContents="skip"/>
|
||||||
|
</xsd:choice>
|
||||||
|
<xsd:attributeGroup ref="AG_Id"/>
|
||||||
|
<xsd:attributeGroup ref="AG_Style"/>
|
||||||
|
<xsd:attribute name="inset" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute ref="o:singleclick"/>
|
||||||
|
<xsd:attribute ref="o:insetmode"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_TextPath">
|
||||||
|
<xsd:attributeGroup ref="AG_Id"/>
|
||||||
|
<xsd:attributeGroup ref="AG_Style"/>
|
||||||
|
<xsd:attribute name="on" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="fitshape" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="fitpath" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="trim" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="xscale" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="string" type="xsd:string" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:element name="arc" type="CT_Arc"/>
|
||||||
|
<xsd:element name="curve" type="CT_Curve"/>
|
||||||
|
<xsd:element name="image" type="CT_Image"/>
|
||||||
|
<xsd:element name="line" type="CT_Line"/>
|
||||||
|
<xsd:element name="oval" type="CT_Oval"/>
|
||||||
|
<xsd:element name="polyline" type="CT_PolyLine"/>
|
||||||
|
<xsd:element name="rect" type="CT_Rect"/>
|
||||||
|
<xsd:element name="roundrect" type="CT_RoundRect"/>
|
||||||
|
<xsd:complexType name="CT_Arc">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:group ref="EG_ShapeElements" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attributeGroup ref="AG_AllCoreAttributes"/>
|
||||||
|
<xsd:attributeGroup ref="AG_AllShapeAttributes"/>
|
||||||
|
<xsd:attribute name="startAngle" type="xsd:decimal" use="optional"/>
|
||||||
|
<xsd:attribute name="endAngle" type="xsd:decimal" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Curve">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:group ref="EG_ShapeElements" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attributeGroup ref="AG_AllCoreAttributes"/>
|
||||||
|
<xsd:attributeGroup ref="AG_AllShapeAttributes"/>
|
||||||
|
<xsd:attribute name="from" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="control1" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="control2" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="to" type="xsd:string" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Image">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:group ref="EG_ShapeElements" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attributeGroup ref="AG_AllCoreAttributes"/>
|
||||||
|
<xsd:attributeGroup ref="AG_AllShapeAttributes"/>
|
||||||
|
<xsd:attributeGroup ref="AG_ImageAttributes"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Line">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:group ref="EG_ShapeElements" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attributeGroup ref="AG_AllCoreAttributes"/>
|
||||||
|
<xsd:attributeGroup ref="AG_AllShapeAttributes"/>
|
||||||
|
<xsd:attribute name="from" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="to" type="xsd:string" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Oval">
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:group ref="EG_ShapeElements" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
</xsd:choice>
|
||||||
|
<xsd:attributeGroup ref="AG_AllCoreAttributes"/>
|
||||||
|
<xsd:attributeGroup ref="AG_AllShapeAttributes"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_PolyLine">
|
||||||
|
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||||
|
<xsd:group ref="EG_ShapeElements"/>
|
||||||
|
<xsd:element ref="o:ink"/>
|
||||||
|
</xsd:choice>
|
||||||
|
<xsd:attributeGroup ref="AG_AllCoreAttributes"/>
|
||||||
|
<xsd:attributeGroup ref="AG_AllShapeAttributes"/>
|
||||||
|
<xsd:attribute name="points" type="xsd:string" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Rect">
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:group ref="EG_ShapeElements" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
</xsd:choice>
|
||||||
|
<xsd:attributeGroup ref="AG_AllCoreAttributes"/>
|
||||||
|
<xsd:attributeGroup ref="AG_AllShapeAttributes"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_RoundRect">
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:group ref="EG_ShapeElements" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
</xsd:choice>
|
||||||
|
<xsd:attributeGroup ref="AG_AllCoreAttributes"/>
|
||||||
|
<xsd:attributeGroup ref="AG_AllShapeAttributes"/>
|
||||||
|
<xsd:attribute name="arcsize" type="xsd:string" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_Ext">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="view"/>
|
||||||
|
<xsd:enumeration value="edit"/>
|
||||||
|
<xsd:enumeration value="backwardCompatible"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_FillType">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="solid"/>
|
||||||
|
<xsd:enumeration value="gradient"/>
|
||||||
|
<xsd:enumeration value="gradientRadial"/>
|
||||||
|
<xsd:enumeration value="tile"/>
|
||||||
|
<xsd:enumeration value="pattern"/>
|
||||||
|
<xsd:enumeration value="frame"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_FillMethod">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="none"/>
|
||||||
|
<xsd:enumeration value="linear"/>
|
||||||
|
<xsd:enumeration value="sigma"/>
|
||||||
|
<xsd:enumeration value="any"/>
|
||||||
|
<xsd:enumeration value="linear sigma"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_ShadowType">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="single"/>
|
||||||
|
<xsd:enumeration value="double"/>
|
||||||
|
<xsd:enumeration value="emboss"/>
|
||||||
|
<xsd:enumeration value="perspective"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_StrokeLineStyle">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="single"/>
|
||||||
|
<xsd:enumeration value="thinThin"/>
|
||||||
|
<xsd:enumeration value="thinThick"/>
|
||||||
|
<xsd:enumeration value="thickThin"/>
|
||||||
|
<xsd:enumeration value="thickBetweenThin"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_StrokeJoinStyle">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="round"/>
|
||||||
|
<xsd:enumeration value="bevel"/>
|
||||||
|
<xsd:enumeration value="miter"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_StrokeEndCap">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="flat"/>
|
||||||
|
<xsd:enumeration value="square"/>
|
||||||
|
<xsd:enumeration value="round"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_StrokeArrowLength">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="short"/>
|
||||||
|
<xsd:enumeration value="medium"/>
|
||||||
|
<xsd:enumeration value="long"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_StrokeArrowWidth">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="narrow"/>
|
||||||
|
<xsd:enumeration value="medium"/>
|
||||||
|
<xsd:enumeration value="wide"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_StrokeArrowType">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="none"/>
|
||||||
|
<xsd:enumeration value="block"/>
|
||||||
|
<xsd:enumeration value="classic"/>
|
||||||
|
<xsd:enumeration value="oval"/>
|
||||||
|
<xsd:enumeration value="diamond"/>
|
||||||
|
<xsd:enumeration value="open"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_ImageAspect">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="ignore"/>
|
||||||
|
<xsd:enumeration value="atMost"/>
|
||||||
|
<xsd:enumeration value="atLeast"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_EditAs">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="canvas"/>
|
||||||
|
<xsd:enumeration value="orgchart"/>
|
||||||
|
<xsd:enumeration value="radial"/>
|
||||||
|
<xsd:enumeration value="cycle"/>
|
||||||
|
<xsd:enumeration value="stacked"/>
|
||||||
|
<xsd:enumeration value="venn"/>
|
||||||
|
<xsd:enumeration value="bullseye"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
</xsd:schema>
|
||||||
@ -0,0 +1,509 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||||
|
xmlns="urn:schemas-microsoft-com:office:office" xmlns:v="urn:schemas-microsoft-com:vml"
|
||||||
|
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
||||||
|
xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||||
|
targetNamespace="urn:schemas-microsoft-com:office:office" elementFormDefault="qualified"
|
||||||
|
attributeFormDefault="unqualified">
|
||||||
|
<xsd:import namespace="urn:schemas-microsoft-com:vml" schemaLocation="vml-main.xsd"/>
|
||||||
|
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
||||||
|
schemaLocation="shared-relationshipReference.xsd"/>
|
||||||
|
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||||
|
schemaLocation="shared-commonSimpleTypes.xsd"/>
|
||||||
|
<xsd:attribute name="bwmode" type="ST_BWMode"/>
|
||||||
|
<xsd:attribute name="bwpure" type="ST_BWMode"/>
|
||||||
|
<xsd:attribute name="bwnormal" type="ST_BWMode"/>
|
||||||
|
<xsd:attribute name="targetscreensize" type="ST_ScreenSize"/>
|
||||||
|
<xsd:attribute name="insetmode" type="ST_InsetMode" default="custom"/>
|
||||||
|
<xsd:attribute name="spt" type="xsd:float"/>
|
||||||
|
<xsd:attribute name="wrapcoords" type="xsd:string"/>
|
||||||
|
<xsd:attribute name="oned" type="s:ST_TrueFalse"/>
|
||||||
|
<xsd:attribute name="regroupid" type="xsd:integer"/>
|
||||||
|
<xsd:attribute name="doubleclicknotify" type="s:ST_TrueFalse"/>
|
||||||
|
<xsd:attribute name="connectortype" type="ST_ConnectorType" default="straight"/>
|
||||||
|
<xsd:attribute name="button" type="s:ST_TrueFalse"/>
|
||||||
|
<xsd:attribute name="userhidden" type="s:ST_TrueFalse"/>
|
||||||
|
<xsd:attribute name="forcedash" type="s:ST_TrueFalse"/>
|
||||||
|
<xsd:attribute name="oleicon" type="s:ST_TrueFalse"/>
|
||||||
|
<xsd:attribute name="ole" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:attribute name="preferrelative" type="s:ST_TrueFalse"/>
|
||||||
|
<xsd:attribute name="cliptowrap" type="s:ST_TrueFalse"/>
|
||||||
|
<xsd:attribute name="clip" type="s:ST_TrueFalse"/>
|
||||||
|
<xsd:attribute name="bullet" type="s:ST_TrueFalse"/>
|
||||||
|
<xsd:attribute name="hr" type="s:ST_TrueFalse"/>
|
||||||
|
<xsd:attribute name="hrstd" type="s:ST_TrueFalse"/>
|
||||||
|
<xsd:attribute name="hrnoshade" type="s:ST_TrueFalse"/>
|
||||||
|
<xsd:attribute name="hrpct" type="xsd:float"/>
|
||||||
|
<xsd:attribute name="hralign" type="ST_HrAlign" default="left"/>
|
||||||
|
<xsd:attribute name="allowincell" type="s:ST_TrueFalse"/>
|
||||||
|
<xsd:attribute name="allowoverlap" type="s:ST_TrueFalse"/>
|
||||||
|
<xsd:attribute name="userdrawn" type="s:ST_TrueFalse"/>
|
||||||
|
<xsd:attribute name="bordertopcolor" type="xsd:string"/>
|
||||||
|
<xsd:attribute name="borderleftcolor" type="xsd:string"/>
|
||||||
|
<xsd:attribute name="borderbottomcolor" type="xsd:string"/>
|
||||||
|
<xsd:attribute name="borderrightcolor" type="xsd:string"/>
|
||||||
|
<xsd:attribute name="connecttype" type="ST_ConnectType"/>
|
||||||
|
<xsd:attribute name="connectlocs" type="xsd:string"/>
|
||||||
|
<xsd:attribute name="connectangles" type="xsd:string"/>
|
||||||
|
<xsd:attribute name="master" type="xsd:string"/>
|
||||||
|
<xsd:attribute name="extrusionok" type="s:ST_TrueFalse"/>
|
||||||
|
<xsd:attribute name="href" type="xsd:string"/>
|
||||||
|
<xsd:attribute name="althref" type="xsd:string"/>
|
||||||
|
<xsd:attribute name="title" type="xsd:string"/>
|
||||||
|
<xsd:attribute name="singleclick" type="s:ST_TrueFalse"/>
|
||||||
|
<xsd:attribute name="oleid" type="xsd:float"/>
|
||||||
|
<xsd:attribute name="detectmouseclick" type="s:ST_TrueFalse"/>
|
||||||
|
<xsd:attribute name="movie" type="xsd:float"/>
|
||||||
|
<xsd:attribute name="spid" type="xsd:string"/>
|
||||||
|
<xsd:attribute name="opacity2" type="xsd:string"/>
|
||||||
|
<xsd:attribute name="relid" type="r:ST_RelationshipId"/>
|
||||||
|
<xsd:attribute name="dgmlayout" type="ST_DiagramLayout"/>
|
||||||
|
<xsd:attribute name="dgmnodekind" type="xsd:integer"/>
|
||||||
|
<xsd:attribute name="dgmlayoutmru" type="ST_DiagramLayout"/>
|
||||||
|
<xsd:attribute name="gfxdata" type="xsd:base64Binary"/>
|
||||||
|
<xsd:attribute name="tableproperties" type="xsd:string"/>
|
||||||
|
<xsd:attribute name="tablelimits" type="xsd:string"/>
|
||||||
|
<xsd:element name="shapedefaults" type="CT_ShapeDefaults"/>
|
||||||
|
<xsd:element name="shapelayout" type="CT_ShapeLayout"/>
|
||||||
|
<xsd:element name="signatureline" type="CT_SignatureLine"/>
|
||||||
|
<xsd:element name="ink" type="CT_Ink"/>
|
||||||
|
<xsd:element name="diagram" type="CT_Diagram"/>
|
||||||
|
<xsd:element name="equationxml" type="CT_EquationXml"/>
|
||||||
|
<xsd:complexType name="CT_ShapeDefaults">
|
||||||
|
<xsd:all minOccurs="0">
|
||||||
|
<xsd:element ref="v:fill" minOccurs="0"/>
|
||||||
|
<xsd:element ref="v:stroke" minOccurs="0"/>
|
||||||
|
<xsd:element ref="v:textbox" minOccurs="0"/>
|
||||||
|
<xsd:element ref="v:shadow" minOccurs="0"/>
|
||||||
|
<xsd:element ref="skew" minOccurs="0"/>
|
||||||
|
<xsd:element ref="extrusion" minOccurs="0"/>
|
||||||
|
<xsd:element ref="callout" minOccurs="0"/>
|
||||||
|
<xsd:element ref="lock" minOccurs="0"/>
|
||||||
|
<xsd:element name="colormru" minOccurs="0" type="CT_ColorMru"/>
|
||||||
|
<xsd:element name="colormenu" minOccurs="0" type="CT_ColorMenu"/>
|
||||||
|
</xsd:all>
|
||||||
|
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||||
|
<xsd:attribute name="spidmax" type="xsd:integer" use="optional"/>
|
||||||
|
<xsd:attribute name="style" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="fill" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="fillcolor" type="s:ST_ColorType" use="optional"/>
|
||||||
|
<xsd:attribute name="stroke" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="strokecolor" type="s:ST_ColorType"/>
|
||||||
|
<xsd:attribute name="allowincell" form="qualified" type="s:ST_TrueFalse"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Ink">
|
||||||
|
<xsd:sequence/>
|
||||||
|
<xsd:attribute name="i" type="xsd:string"/>
|
||||||
|
<xsd:attribute name="annotation" type="s:ST_TrueFalse"/>
|
||||||
|
<xsd:attribute name="contentType" type="ST_ContentType" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_SignatureLine">
|
||||||
|
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||||
|
<xsd:attribute name="issignatureline" type="s:ST_TrueFalse"/>
|
||||||
|
<xsd:attribute name="id" type="s:ST_Guid"/>
|
||||||
|
<xsd:attribute name="provid" type="s:ST_Guid"/>
|
||||||
|
<xsd:attribute name="signinginstructionsset" type="s:ST_TrueFalse"/>
|
||||||
|
<xsd:attribute name="allowcomments" type="s:ST_TrueFalse"/>
|
||||||
|
<xsd:attribute name="showsigndate" type="s:ST_TrueFalse"/>
|
||||||
|
<xsd:attribute name="suggestedsigner" type="xsd:string" form="qualified"/>
|
||||||
|
<xsd:attribute name="suggestedsigner2" type="xsd:string" form="qualified"/>
|
||||||
|
<xsd:attribute name="suggestedsigneremail" type="xsd:string" form="qualified"/>
|
||||||
|
<xsd:attribute name="signinginstructions" type="xsd:string"/>
|
||||||
|
<xsd:attribute name="addlxml" type="xsd:string"/>
|
||||||
|
<xsd:attribute name="sigprovurl" type="xsd:string"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_ShapeLayout">
|
||||||
|
<xsd:all>
|
||||||
|
<xsd:element name="idmap" type="CT_IdMap" minOccurs="0"/>
|
||||||
|
<xsd:element name="regrouptable" type="CT_RegroupTable" minOccurs="0"/>
|
||||||
|
<xsd:element name="rules" type="CT_Rules" minOccurs="0"/>
|
||||||
|
</xsd:all>
|
||||||
|
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_IdMap">
|
||||||
|
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||||
|
<xsd:attribute name="data" type="xsd:string" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_RegroupTable">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="entry" type="CT_Entry" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Entry">
|
||||||
|
<xsd:attribute name="new" type="xsd:int" use="optional"/>
|
||||||
|
<xsd:attribute name="old" type="xsd:int" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Rules">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="r" type="CT_R" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_R">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="proxy" type="CT_Proxy" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="id" type="xsd:string" use="required"/>
|
||||||
|
<xsd:attribute name="type" type="ST_RType" use="optional"/>
|
||||||
|
<xsd:attribute name="how" type="ST_How" use="optional"/>
|
||||||
|
<xsd:attribute name="idref" type="xsd:string" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Proxy">
|
||||||
|
<xsd:attribute name="start" type="s:ST_TrueFalseBlank" use="optional" default="false"/>
|
||||||
|
<xsd:attribute name="end" type="s:ST_TrueFalseBlank" use="optional" default="false"/>
|
||||||
|
<xsd:attribute name="idref" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="connectloc" type="xsd:int" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Diagram">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="relationtable" type="CT_RelationTable" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||||
|
<xsd:attribute name="dgmstyle" type="xsd:integer" use="optional"/>
|
||||||
|
<xsd:attribute name="autoformat" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="reverse" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="autolayout" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="dgmscalex" type="xsd:integer" use="optional"/>
|
||||||
|
<xsd:attribute name="dgmscaley" type="xsd:integer" use="optional"/>
|
||||||
|
<xsd:attribute name="dgmfontsize" type="xsd:integer" use="optional"/>
|
||||||
|
<xsd:attribute name="constrainbounds" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="dgmbasetextscale" type="xsd:integer" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_EquationXml">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:any namespace="##any"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="contentType" type="ST_AlternateMathContentType" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_AlternateMathContentType">
|
||||||
|
<xsd:restriction base="xsd:string"/>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_RelationTable">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="rel" type="CT_Relation" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Relation">
|
||||||
|
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||||
|
<xsd:attribute name="idsrc" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="iddest" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="idcntr" type="xsd:string" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_ColorMru">
|
||||||
|
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||||
|
<xsd:attribute name="colors" type="xsd:string"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_ColorMenu">
|
||||||
|
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||||
|
<xsd:attribute name="strokecolor" type="s:ST_ColorType"/>
|
||||||
|
<xsd:attribute name="fillcolor" type="s:ST_ColorType"/>
|
||||||
|
<xsd:attribute name="shadowcolor" type="s:ST_ColorType"/>
|
||||||
|
<xsd:attribute name="extrusioncolor" type="s:ST_ColorType"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:element name="skew" type="CT_Skew"/>
|
||||||
|
<xsd:element name="extrusion" type="CT_Extrusion"/>
|
||||||
|
<xsd:element name="callout" type="CT_Callout"/>
|
||||||
|
<xsd:element name="lock" type="CT_Lock"/>
|
||||||
|
<xsd:element name="OLEObject" type="CT_OLEObject"/>
|
||||||
|
<xsd:element name="complex" type="CT_Complex"/>
|
||||||
|
<xsd:element name="left" type="CT_StrokeChild"/>
|
||||||
|
<xsd:element name="top" type="CT_StrokeChild"/>
|
||||||
|
<xsd:element name="right" type="CT_StrokeChild"/>
|
||||||
|
<xsd:element name="bottom" type="CT_StrokeChild"/>
|
||||||
|
<xsd:element name="column" type="CT_StrokeChild"/>
|
||||||
|
<xsd:element name="clippath" type="CT_ClipPath"/>
|
||||||
|
<xsd:element name="fill" type="CT_Fill"/>
|
||||||
|
<xsd:complexType name="CT_Skew">
|
||||||
|
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||||
|
<xsd:attribute name="id" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="on" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="offset" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="origin" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="matrix" type="xsd:string" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Extrusion">
|
||||||
|
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||||
|
<xsd:attribute name="on" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="type" type="ST_ExtrusionType" default="parallel" use="optional"/>
|
||||||
|
<xsd:attribute name="render" type="ST_ExtrusionRender" default="solid" use="optional"/>
|
||||||
|
<xsd:attribute name="viewpointorigin" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="viewpoint" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="plane" type="ST_ExtrusionPlane" default="XY" use="optional"/>
|
||||||
|
<xsd:attribute name="skewangle" type="xsd:float" use="optional"/>
|
||||||
|
<xsd:attribute name="skewamt" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="foredepth" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="backdepth" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="orientation" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="orientationangle" type="xsd:float" use="optional"/>
|
||||||
|
<xsd:attribute name="lockrotationcenter" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="autorotationcenter" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="rotationcenter" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="rotationangle" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="colormode" type="ST_ColorMode" use="optional"/>
|
||||||
|
<xsd:attribute name="color" type="s:ST_ColorType" use="optional"/>
|
||||||
|
<xsd:attribute name="shininess" type="xsd:float" use="optional"/>
|
||||||
|
<xsd:attribute name="specularity" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="diffusity" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="metal" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="edge" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="facet" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="lightface" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="brightness" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="lightposition" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="lightlevel" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="lightharsh" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="lightposition2" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="lightlevel2" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="lightharsh2" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Callout">
|
||||||
|
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||||
|
<xsd:attribute name="on" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="type" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="gap" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="angle" type="ST_Angle" use="optional"/>
|
||||||
|
<xsd:attribute name="dropauto" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="drop" type="ST_CalloutDrop" use="optional"/>
|
||||||
|
<xsd:attribute name="distance" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="lengthspecified" type="s:ST_TrueFalse" default="f" use="optional"/>
|
||||||
|
<xsd:attribute name="length" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="accentbar" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="textborder" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="minusx" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="minusy" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Lock">
|
||||||
|
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||||
|
<xsd:attribute name="position" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="selection" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="grouping" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="ungrouping" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="rotation" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="cropping" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="verticies" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="adjusthandles" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="text" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="aspectratio" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="shapetype" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_OLEObject">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="LinkType" type="ST_OLELinkType" minOccurs="0"/>
|
||||||
|
<xsd:element name="LockedField" type="s:ST_TrueFalseBlank" minOccurs="0"/>
|
||||||
|
<xsd:element name="FieldCodes" type="xsd:string" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="Type" type="ST_OLEType" use="optional"/>
|
||||||
|
<xsd:attribute name="ProgID" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="ShapeID" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="DrawAspect" type="ST_OLEDrawAspect" use="optional"/>
|
||||||
|
<xsd:attribute name="ObjectID" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute ref="r:id" use="optional"/>
|
||||||
|
<xsd:attribute name="UpdateMode" type="ST_OLEUpdateMode" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Complex">
|
||||||
|
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_StrokeChild">
|
||||||
|
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||||
|
<xsd:attribute name="on" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="weight" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="color" type="s:ST_ColorType" use="optional"/>
|
||||||
|
<xsd:attribute name="color2" type="s:ST_ColorType" use="optional"/>
|
||||||
|
<xsd:attribute name="opacity" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="linestyle" type="v:ST_StrokeLineStyle" use="optional"/>
|
||||||
|
<xsd:attribute name="miterlimit" type="xsd:decimal" use="optional"/>
|
||||||
|
<xsd:attribute name="joinstyle" type="v:ST_StrokeJoinStyle" use="optional"/>
|
||||||
|
<xsd:attribute name="endcap" type="v:ST_StrokeEndCap" use="optional"/>
|
||||||
|
<xsd:attribute name="dashstyle" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="insetpen" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="filltype" type="v:ST_FillType" use="optional"/>
|
||||||
|
<xsd:attribute name="src" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="imageaspect" type="v:ST_ImageAspect" use="optional"/>
|
||||||
|
<xsd:attribute name="imagesize" type="xsd:string" use="optional"/>
|
||||||
|
<xsd:attribute name="imagealignshape" type="s:ST_TrueFalse" use="optional"/>
|
||||||
|
<xsd:attribute name="startarrow" type="v:ST_StrokeArrowType" use="optional"/>
|
||||||
|
<xsd:attribute name="startarrowwidth" type="v:ST_StrokeArrowWidth" use="optional"/>
|
||||||
|
<xsd:attribute name="startarrowlength" type="v:ST_StrokeArrowLength" use="optional"/>
|
||||||
|
<xsd:attribute name="endarrow" type="v:ST_StrokeArrowType" use="optional"/>
|
||||||
|
<xsd:attribute name="endarrowwidth" type="v:ST_StrokeArrowWidth" use="optional"/>
|
||||||
|
<xsd:attribute name="endarrowlength" type="v:ST_StrokeArrowLength" use="optional"/>
|
||||||
|
<xsd:attribute ref="href"/>
|
||||||
|
<xsd:attribute ref="althref"/>
|
||||||
|
<xsd:attribute ref="title"/>
|
||||||
|
<xsd:attribute ref="forcedash"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_ClipPath">
|
||||||
|
<xsd:attribute name="v" type="xsd:string" use="required" form="qualified"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Fill">
|
||||||
|
<xsd:attributeGroup ref="v:AG_Ext"/>
|
||||||
|
<xsd:attribute name="type" type="ST_FillType"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_RType">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="arc"/>
|
||||||
|
<xsd:enumeration value="callout"/>
|
||||||
|
<xsd:enumeration value="connector"/>
|
||||||
|
<xsd:enumeration value="align"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_How">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="top"/>
|
||||||
|
<xsd:enumeration value="middle"/>
|
||||||
|
<xsd:enumeration value="bottom"/>
|
||||||
|
<xsd:enumeration value="left"/>
|
||||||
|
<xsd:enumeration value="center"/>
|
||||||
|
<xsd:enumeration value="right"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_BWMode">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="color"/>
|
||||||
|
<xsd:enumeration value="auto"/>
|
||||||
|
<xsd:enumeration value="grayScale"/>
|
||||||
|
<xsd:enumeration value="lightGrayscale"/>
|
||||||
|
<xsd:enumeration value="inverseGray"/>
|
||||||
|
<xsd:enumeration value="grayOutline"/>
|
||||||
|
<xsd:enumeration value="highContrast"/>
|
||||||
|
<xsd:enumeration value="black"/>
|
||||||
|
<xsd:enumeration value="white"/>
|
||||||
|
<xsd:enumeration value="hide"/>
|
||||||
|
<xsd:enumeration value="undrawn"/>
|
||||||
|
<xsd:enumeration value="blackTextAndLines"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_ScreenSize">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="544,376"/>
|
||||||
|
<xsd:enumeration value="640,480"/>
|
||||||
|
<xsd:enumeration value="720,512"/>
|
||||||
|
<xsd:enumeration value="800,600"/>
|
||||||
|
<xsd:enumeration value="1024,768"/>
|
||||||
|
<xsd:enumeration value="1152,862"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_InsetMode">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="auto"/>
|
||||||
|
<xsd:enumeration value="custom"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_ColorMode">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="auto"/>
|
||||||
|
<xsd:enumeration value="custom"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_ContentType">
|
||||||
|
<xsd:restriction base="xsd:string"/>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_DiagramLayout">
|
||||||
|
<xsd:restriction base="xsd:integer">
|
||||||
|
<xsd:enumeration value="0"/>
|
||||||
|
<xsd:enumeration value="1"/>
|
||||||
|
<xsd:enumeration value="2"/>
|
||||||
|
<xsd:enumeration value="3"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_ExtrusionType">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="perspective"/>
|
||||||
|
<xsd:enumeration value="parallel"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_ExtrusionRender">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="solid"/>
|
||||||
|
<xsd:enumeration value="wireFrame"/>
|
||||||
|
<xsd:enumeration value="boundingCube"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_ExtrusionPlane">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="XY"/>
|
||||||
|
<xsd:enumeration value="ZX"/>
|
||||||
|
<xsd:enumeration value="YZ"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_Angle">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="any"/>
|
||||||
|
<xsd:enumeration value="30"/>
|
||||||
|
<xsd:enumeration value="45"/>
|
||||||
|
<xsd:enumeration value="60"/>
|
||||||
|
<xsd:enumeration value="90"/>
|
||||||
|
<xsd:enumeration value="auto"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_CalloutDrop">
|
||||||
|
<xsd:restriction base="xsd:string"/>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_CalloutPlacement">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="top"/>
|
||||||
|
<xsd:enumeration value="center"/>
|
||||||
|
<xsd:enumeration value="bottom"/>
|
||||||
|
<xsd:enumeration value="user"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_ConnectorType">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="none"/>
|
||||||
|
<xsd:enumeration value="straight"/>
|
||||||
|
<xsd:enumeration value="elbow"/>
|
||||||
|
<xsd:enumeration value="curved"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_HrAlign">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="left"/>
|
||||||
|
<xsd:enumeration value="right"/>
|
||||||
|
<xsd:enumeration value="center"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_ConnectType">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="none"/>
|
||||||
|
<xsd:enumeration value="rect"/>
|
||||||
|
<xsd:enumeration value="segments"/>
|
||||||
|
<xsd:enumeration value="custom"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_OLELinkType">
|
||||||
|
<xsd:restriction base="xsd:string"/>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_OLEType">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="Embed"/>
|
||||||
|
<xsd:enumeration value="Link"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_OLEDrawAspect">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="Content"/>
|
||||||
|
<xsd:enumeration value="Icon"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_OLEUpdateMode">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="Always"/>
|
||||||
|
<xsd:enumeration value="OnCall"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_FillType">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="gradientCenter"/>
|
||||||
|
<xsd:enumeration value="solid"/>
|
||||||
|
<xsd:enumeration value="pattern"/>
|
||||||
|
<xsd:enumeration value="tile"/>
|
||||||
|
<xsd:enumeration value="frame"/>
|
||||||
|
<xsd:enumeration value="gradientUnscaled"/>
|
||||||
|
<xsd:enumeration value="gradientRadial"/>
|
||||||
|
<xsd:enumeration value="gradient"/>
|
||||||
|
<xsd:enumeration value="background"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
</xsd:schema>
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
<?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>
|
||||||
@ -0,0 +1,108 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||||
|
xmlns="urn:schemas-microsoft-com:office:excel"
|
||||||
|
xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||||
|
targetNamespace="urn:schemas-microsoft-com:office:excel" elementFormDefault="qualified"
|
||||||
|
attributeFormDefault="unqualified">
|
||||||
|
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||||
|
schemaLocation="shared-commonSimpleTypes.xsd"/>
|
||||||
|
<xsd:element name="ClientData" type="CT_ClientData"/>
|
||||||
|
<xsd:complexType name="CT_ClientData">
|
||||||
|
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||||
|
<xsd:element name="MoveWithCells" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:element name="SizeWithCells" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:element name="Anchor" type="xsd:string"/>
|
||||||
|
<xsd:element name="Locked" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:element name="DefaultSize" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:element name="PrintObject" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:element name="Disabled" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:element name="AutoFill" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:element name="AutoLine" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:element name="AutoPict" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:element name="FmlaMacro" type="xsd:string"/>
|
||||||
|
<xsd:element name="TextHAlign" type="xsd:string"/>
|
||||||
|
<xsd:element name="TextVAlign" type="xsd:string"/>
|
||||||
|
<xsd:element name="LockText" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:element name="JustLastX" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:element name="SecretEdit" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:element name="Default" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:element name="Help" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:element name="Cancel" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:element name="Dismiss" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:element name="Accel" type="xsd:integer"/>
|
||||||
|
<xsd:element name="Accel2" type="xsd:integer"/>
|
||||||
|
<xsd:element name="Row" type="xsd:integer"/>
|
||||||
|
<xsd:element name="Column" type="xsd:integer"/>
|
||||||
|
<xsd:element name="Visible" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:element name="RowHidden" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:element name="ColHidden" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:element name="VTEdit" type="xsd:integer"/>
|
||||||
|
<xsd:element name="MultiLine" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:element name="VScroll" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:element name="ValidIds" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:element name="FmlaRange" type="xsd:string"/>
|
||||||
|
<xsd:element name="WidthMin" type="xsd:integer"/>
|
||||||
|
<xsd:element name="Sel" type="xsd:integer"/>
|
||||||
|
<xsd:element name="NoThreeD2" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:element name="SelType" type="xsd:string"/>
|
||||||
|
<xsd:element name="MultiSel" type="xsd:string"/>
|
||||||
|
<xsd:element name="LCT" type="xsd:string"/>
|
||||||
|
<xsd:element name="ListItem" type="xsd:string"/>
|
||||||
|
<xsd:element name="DropStyle" type="xsd:string"/>
|
||||||
|
<xsd:element name="Colored" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:element name="DropLines" type="xsd:integer"/>
|
||||||
|
<xsd:element name="Checked" type="xsd:integer"/>
|
||||||
|
<xsd:element name="FmlaLink" type="xsd:string"/>
|
||||||
|
<xsd:element name="FmlaPict" type="xsd:string"/>
|
||||||
|
<xsd:element name="NoThreeD" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:element name="FirstButton" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:element name="FmlaGroup" type="xsd:string"/>
|
||||||
|
<xsd:element name="Val" type="xsd:integer"/>
|
||||||
|
<xsd:element name="Min" type="xsd:integer"/>
|
||||||
|
<xsd:element name="Max" type="xsd:integer"/>
|
||||||
|
<xsd:element name="Inc" type="xsd:integer"/>
|
||||||
|
<xsd:element name="Page" type="xsd:integer"/>
|
||||||
|
<xsd:element name="Horiz" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:element name="Dx" type="xsd:integer"/>
|
||||||
|
<xsd:element name="MapOCX" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:element name="CF" type="ST_CF"/>
|
||||||
|
<xsd:element name="Camera" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:element name="RecalcAlways" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:element name="AutoScale" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:element name="DDE" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:element name="UIObj" type="s:ST_TrueFalseBlank"/>
|
||||||
|
<xsd:element name="ScriptText" type="xsd:string"/>
|
||||||
|
<xsd:element name="ScriptExtended" type="xsd:string"/>
|
||||||
|
<xsd:element name="ScriptLanguage" type="xsd:nonNegativeInteger"/>
|
||||||
|
<xsd:element name="ScriptLocation" type="xsd:nonNegativeInteger"/>
|
||||||
|
<xsd:element name="FmlaTxbx" type="xsd:string"/>
|
||||||
|
</xsd:choice>
|
||||||
|
<xsd:attribute name="ObjectType" type="ST_ObjectType" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_CF">
|
||||||
|
<xsd:restriction base="xsd:string"/>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_ObjectType">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="Button"/>
|
||||||
|
<xsd:enumeration value="Checkbox"/>
|
||||||
|
<xsd:enumeration value="Dialog"/>
|
||||||
|
<xsd:enumeration value="Drop"/>
|
||||||
|
<xsd:enumeration value="Edit"/>
|
||||||
|
<xsd:enumeration value="GBox"/>
|
||||||
|
<xsd:enumeration value="Label"/>
|
||||||
|
<xsd:enumeration value="LineA"/>
|
||||||
|
<xsd:enumeration value="List"/>
|
||||||
|
<xsd:enumeration value="Movie"/>
|
||||||
|
<xsd:enumeration value="Note"/>
|
||||||
|
<xsd:enumeration value="Pict"/>
|
||||||
|
<xsd:enumeration value="Radio"/>
|
||||||
|
<xsd:enumeration value="RectA"/>
|
||||||
|
<xsd:enumeration value="Scroll"/>
|
||||||
|
<xsd:enumeration value="Spin"/>
|
||||||
|
<xsd:enumeration value="Shape"/>
|
||||||
|
<xsd:enumeration value="Group"/>
|
||||||
|
<xsd:enumeration value="Rect"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
</xsd:schema>
|
||||||
@ -0,0 +1,96 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||||
|
xmlns="urn:schemas-microsoft-com:office:word"
|
||||||
|
targetNamespace="urn:schemas-microsoft-com:office:word" elementFormDefault="qualified"
|
||||||
|
attributeFormDefault="unqualified">
|
||||||
|
<xsd:element name="bordertop" type="CT_Border"/>
|
||||||
|
<xsd:element name="borderleft" type="CT_Border"/>
|
||||||
|
<xsd:element name="borderright" type="CT_Border"/>
|
||||||
|
<xsd:element name="borderbottom" type="CT_Border"/>
|
||||||
|
<xsd:complexType name="CT_Border">
|
||||||
|
<xsd:attribute name="type" type="ST_BorderType" use="optional"/>
|
||||||
|
<xsd:attribute name="width" type="xsd:positiveInteger" use="optional"/>
|
||||||
|
<xsd:attribute name="shadow" type="ST_BorderShadow" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:element name="wrap" type="CT_Wrap"/>
|
||||||
|
<xsd:complexType name="CT_Wrap">
|
||||||
|
<xsd:attribute name="type" type="ST_WrapType" use="optional"/>
|
||||||
|
<xsd:attribute name="side" type="ST_WrapSide" use="optional"/>
|
||||||
|
<xsd:attribute name="anchorx" type="ST_HorizontalAnchor" use="optional"/>
|
||||||
|
<xsd:attribute name="anchory" type="ST_VerticalAnchor" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:element name="anchorlock" type="CT_AnchorLock"/>
|
||||||
|
<xsd:complexType name="CT_AnchorLock"/>
|
||||||
|
<xsd:simpleType name="ST_BorderType">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="none"/>
|
||||||
|
<xsd:enumeration value="single"/>
|
||||||
|
<xsd:enumeration value="thick"/>
|
||||||
|
<xsd:enumeration value="double"/>
|
||||||
|
<xsd:enumeration value="hairline"/>
|
||||||
|
<xsd:enumeration value="dot"/>
|
||||||
|
<xsd:enumeration value="dash"/>
|
||||||
|
<xsd:enumeration value="dotDash"/>
|
||||||
|
<xsd:enumeration value="dashDotDot"/>
|
||||||
|
<xsd:enumeration value="triple"/>
|
||||||
|
<xsd:enumeration value="thinThickSmall"/>
|
||||||
|
<xsd:enumeration value="thickThinSmall"/>
|
||||||
|
<xsd:enumeration value="thickBetweenThinSmall"/>
|
||||||
|
<xsd:enumeration value="thinThick"/>
|
||||||
|
<xsd:enumeration value="thickThin"/>
|
||||||
|
<xsd:enumeration value="thickBetweenThin"/>
|
||||||
|
<xsd:enumeration value="thinThickLarge"/>
|
||||||
|
<xsd:enumeration value="thickThinLarge"/>
|
||||||
|
<xsd:enumeration value="thickBetweenThinLarge"/>
|
||||||
|
<xsd:enumeration value="wave"/>
|
||||||
|
<xsd:enumeration value="doubleWave"/>
|
||||||
|
<xsd:enumeration value="dashedSmall"/>
|
||||||
|
<xsd:enumeration value="dashDotStroked"/>
|
||||||
|
<xsd:enumeration value="threeDEmboss"/>
|
||||||
|
<xsd:enumeration value="threeDEngrave"/>
|
||||||
|
<xsd:enumeration value="HTMLOutset"/>
|
||||||
|
<xsd:enumeration value="HTMLInset"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_BorderShadow">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="t"/>
|
||||||
|
<xsd:enumeration value="true"/>
|
||||||
|
<xsd:enumeration value="f"/>
|
||||||
|
<xsd:enumeration value="false"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_WrapType">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="topAndBottom"/>
|
||||||
|
<xsd:enumeration value="square"/>
|
||||||
|
<xsd:enumeration value="none"/>
|
||||||
|
<xsd:enumeration value="tight"/>
|
||||||
|
<xsd:enumeration value="through"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_WrapSide">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="both"/>
|
||||||
|
<xsd:enumeration value="left"/>
|
||||||
|
<xsd:enumeration value="right"/>
|
||||||
|
<xsd:enumeration value="largest"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_HorizontalAnchor">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="margin"/>
|
||||||
|
<xsd:enumeration value="page"/>
|
||||||
|
<xsd:enumeration value="text"/>
|
||||||
|
<xsd:enumeration value="char"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_VerticalAnchor">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="margin"/>
|
||||||
|
<xsd:enumeration value="page"/>
|
||||||
|
<xsd:enumeration value="text"/>
|
||||||
|
<xsd:enumeration value="line"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
</xsd:schema>
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,116 @@
|
|||||||
|
<?xml version='1.0'?>
|
||||||
|
<xs:schema targetNamespace="http://www.w3.org/XML/1998/namespace" xmlns:xs="http://www.w3.org/2001/XMLSchema" xml:lang="en">
|
||||||
|
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
See http://www.w3.org/XML/1998/namespace.html and
|
||||||
|
http://www.w3.org/TR/REC-xml for information about this namespace.
|
||||||
|
|
||||||
|
This schema document describes the XML namespace, in a form
|
||||||
|
suitable for import by other schema documents.
|
||||||
|
|
||||||
|
Note that local names in this namespace are intended to be defined
|
||||||
|
only by the World Wide Web Consortium or its subgroups. The
|
||||||
|
following names are currently defined in this namespace and should
|
||||||
|
not be used with conflicting semantics by any Working Group,
|
||||||
|
specification, or document instance:
|
||||||
|
|
||||||
|
base (as an attribute name): denotes an attribute whose value
|
||||||
|
provides a URI to be used as the base for interpreting any
|
||||||
|
relative URIs in the scope of the element on which it
|
||||||
|
appears; its value is inherited. This name is reserved
|
||||||
|
by virtue of its definition in the XML Base specification.
|
||||||
|
|
||||||
|
lang (as an attribute name): denotes an attribute whose value
|
||||||
|
is a language code for the natural language of the content of
|
||||||
|
any element; its value is inherited. This name is reserved
|
||||||
|
by virtue of its definition in the XML specification.
|
||||||
|
|
||||||
|
space (as an attribute name): denotes an attribute whose
|
||||||
|
value is a keyword indicating what whitespace processing
|
||||||
|
discipline is intended for the content of the element; its
|
||||||
|
value is inherited. This name is reserved by virtue of its
|
||||||
|
definition in the XML specification.
|
||||||
|
|
||||||
|
Father (in any context at all): denotes Jon Bosak, the chair of
|
||||||
|
the original XML Working Group. This name is reserved by
|
||||||
|
the following decision of the W3C XML Plenary and
|
||||||
|
XML Coordination groups:
|
||||||
|
|
||||||
|
In appreciation for his vision, leadership and dedication
|
||||||
|
the W3C XML Plenary on this 10th day of February, 2000
|
||||||
|
reserves for Jon Bosak in perpetuity the XML name
|
||||||
|
xml:Father
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>This schema defines attributes and an attribute group
|
||||||
|
suitable for use by
|
||||||
|
schemas wishing to allow xml:base, xml:lang or xml:space attributes
|
||||||
|
on elements they define.
|
||||||
|
|
||||||
|
To enable this, such a schema must import this schema
|
||||||
|
for the XML namespace, e.g. as follows:
|
||||||
|
<schema . . .>
|
||||||
|
. . .
|
||||||
|
<import namespace="http://www.w3.org/XML/1998/namespace"
|
||||||
|
schemaLocation="http://www.w3.org/2001/03/xml.xsd"/>
|
||||||
|
|
||||||
|
Subsequently, qualified reference to any of the attributes
|
||||||
|
or the group defined below will have the desired effect, e.g.
|
||||||
|
|
||||||
|
<type . . .>
|
||||||
|
. . .
|
||||||
|
<attributeGroup ref="xml:specialAttrs"/>
|
||||||
|
|
||||||
|
will define a type which will schema-validate an instance
|
||||||
|
element with any of those attributes</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>In keeping with the XML Schema WG's standard versioning
|
||||||
|
policy, this schema document will persist at
|
||||||
|
http://www.w3.org/2001/03/xml.xsd.
|
||||||
|
At the date of issue it can also be found at
|
||||||
|
http://www.w3.org/2001/xml.xsd.
|
||||||
|
The schema document at that URI may however change in the future,
|
||||||
|
in order to remain compatible with the latest version of XML Schema
|
||||||
|
itself. In other words, if the XML Schema namespace changes, the version
|
||||||
|
of this document at
|
||||||
|
http://www.w3.org/2001/xml.xsd will change
|
||||||
|
accordingly; the version at
|
||||||
|
http://www.w3.org/2001/03/xml.xsd will not change.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
|
||||||
|
<xs:attribute name="lang" type="xs:language">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>In due course, we should install the relevant ISO 2- and 3-letter
|
||||||
|
codes as the enumerated possible values . . .</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
|
||||||
|
<xs:attribute name="space" default="preserve">
|
||||||
|
<xs:simpleType>
|
||||||
|
<xs:restriction base="xs:NCName">
|
||||||
|
<xs:enumeration value="default"/>
|
||||||
|
<xs:enumeration value="preserve"/>
|
||||||
|
</xs:restriction>
|
||||||
|
</xs:simpleType>
|
||||||
|
</xs:attribute>
|
||||||
|
|
||||||
|
<xs:attribute name="base" type="xs:anyURI">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>See http://www.w3.org/TR/xmlbase/ for
|
||||||
|
information about this attribute.</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
</xs:attribute>
|
||||||
|
|
||||||
|
<xs:attributeGroup name="specialAttrs">
|
||||||
|
<xs:attribute ref="xml:base"/>
|
||||||
|
<xs:attribute ref="xml:lang"/>
|
||||||
|
<xs:attribute ref="xml:space"/>
|
||||||
|
</xs:attributeGroup>
|
||||||
|
|
||||||
|
</xs:schema>
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
<?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>
|
||||||
@ -0,0 +1,50 @@
|
|||||||
|
<?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>
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
<?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>
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
<?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>
|
||||||
@ -0,0 +1,75 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<xsd:schema xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
attributeFormDefault="unqualified" elementFormDefault="qualified"
|
||||||
|
targetNamespace="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
This XSD is a modified version of the one found at:
|
||||||
|
https://github.com/plutext/docx4j/blob/master/xsd/mce/markup-compatibility-2006-MINIMAL.xsd
|
||||||
|
|
||||||
|
This XSD has 2 objectives:
|
||||||
|
|
||||||
|
1. round tripping @mc:Ignorable
|
||||||
|
|
||||||
|
<w:document
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
|
||||||
|
mc:Ignorable="w14 w15 wp14">
|
||||||
|
|
||||||
|
2. enabling AlternateContent to be manipulated in certain elements
|
||||||
|
(in the unusual case where the content model is xsd:any, it doesn't have to be explicitly added)
|
||||||
|
|
||||||
|
See further ECMA-376, 4th Edition, Office Open XML File Formats
|
||||||
|
Part 3 : Markup Compatibility and Extensibility
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Objective 1 -->
|
||||||
|
<xsd:attribute name="Ignorable" type="xsd:string" />
|
||||||
|
|
||||||
|
<!-- Objective 2 -->
|
||||||
|
<xsd:attribute name="MustUnderstand" type="xsd:string" />
|
||||||
|
<xsd:attribute name="ProcessContent" type="xsd:string" />
|
||||||
|
|
||||||
|
<!-- An AlternateContent element shall contain one or more Choice child elements, optionally followed by a
|
||||||
|
Fallback child element. If present, there shall be only one Fallback element, and it shall follow all Choice
|
||||||
|
elements. -->
|
||||||
|
<xsd:element name="AlternateContent">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="Choice" minOccurs="0" maxOccurs="unbounded">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:any minOccurs="0" maxOccurs="unbounded"
|
||||||
|
processContents="strict">
|
||||||
|
</xsd:any>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="Requires" type="xsd:string" use="required" />
|
||||||
|
<xsd:attribute ref="mc:Ignorable" use="optional" />
|
||||||
|
<xsd:attribute ref="mc:MustUnderstand" use="optional" />
|
||||||
|
<xsd:attribute ref="mc:ProcessContent" use="optional" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="Fallback" minOccurs="0" maxOccurs="1">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:any minOccurs="0" maxOccurs="unbounded"
|
||||||
|
processContents="strict">
|
||||||
|
</xsd:any>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute ref="mc:Ignorable" use="optional" />
|
||||||
|
<xsd:attribute ref="mc:MustUnderstand" use="optional" />
|
||||||
|
<xsd:attribute ref="mc:ProcessContent" use="optional" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:sequence>
|
||||||
|
<!-- AlternateContent elements might include the attributes Ignorable,
|
||||||
|
MustUnderstand and ProcessContent described in this Part of ECMA-376. These
|
||||||
|
attributes’ qualified names shall be prefixed when associated with an AlternateContent
|
||||||
|
element. -->
|
||||||
|
<xsd:attribute ref="mc:Ignorable" use="optional" />
|
||||||
|
<xsd:attribute ref="mc:MustUnderstand" use="optional" />
|
||||||
|
<xsd:attribute ref="mc:ProcessContent" use="optional" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
@ -0,0 +1,560 @@
|
|||||||
|
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:w12="http://schemas.openxmlformats.org/wordprocessingml/2006/main" elementFormDefault="qualified" attributeFormDefault="qualified" blockDefault="#all" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns="http://schemas.microsoft.com/office/word/2010/wordml" targetNamespace="http://schemas.microsoft.com/office/word/2010/wordml">
|
||||||
|
<!-- <xsd:import id="rel" namespace="http://schemas.openxmlformats.org/officeDocument/2006/relationships" schemaLocation="orel.xsd"/> -->
|
||||||
|
<xsd:import id="w" namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main" schemaLocation="../ISO-IEC29500-4_2016/wml.xsd"/>
|
||||||
|
<!-- <xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/main" schemaLocation="oartbasetypes.xsd"/>
|
||||||
|
<xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/main" schemaLocation="oartsplineproperties.xsd"/> -->
|
||||||
|
<xsd:complexType name="CT_LongHexNumber">
|
||||||
|
<xsd:attribute name="val" type="w:ST_LongHexNumber" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_OnOff">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="true"/>
|
||||||
|
<xsd:enumeration value="false"/>
|
||||||
|
<xsd:enumeration value="0"/>
|
||||||
|
<xsd:enumeration value="1"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_OnOff">
|
||||||
|
<xsd:attribute name="val" type="ST_OnOff"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:element name="docId" type="CT_LongHexNumber"/>
|
||||||
|
<xsd:element name="conflictMode" type="CT_OnOff"/>
|
||||||
|
<xsd:attributeGroup name="AG_Parids">
|
||||||
|
<xsd:attribute name="paraId" type="w:ST_LongHexNumber"/>
|
||||||
|
<xsd:attribute name="textId" type="w:ST_LongHexNumber"/>
|
||||||
|
</xsd:attributeGroup>
|
||||||
|
<xsd:attribute name="anchorId" type="w:ST_LongHexNumber"/>
|
||||||
|
<xsd:attribute name="noSpellErr" type="ST_OnOff"/>
|
||||||
|
<xsd:element name="customXmlConflictInsRangeStart" type="w:CT_TrackChange"/>
|
||||||
|
<xsd:element name="customXmlConflictInsRangeEnd" type="w:CT_Markup"/>
|
||||||
|
<xsd:element name="customXmlConflictDelRangeStart" type="w:CT_TrackChange"/>
|
||||||
|
<xsd:element name="customXmlConflictDelRangeEnd" type="w:CT_Markup"/>
|
||||||
|
<xsd:group name="EG_RunLevelConflicts">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="conflictIns" type="w:CT_RunTrackChange" minOccurs="0"/>
|
||||||
|
<xsd:element name="conflictDel" type="w:CT_RunTrackChange" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:group>
|
||||||
|
<xsd:group name="EG_Conflicts">
|
||||||
|
<xsd:choice>
|
||||||
|
<xsd:element name="conflictIns" type="w:CT_TrackChange" minOccurs="0"/>
|
||||||
|
<xsd:element name="conflictDel" type="w:CT_TrackChange" minOccurs="0"/>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:group>
|
||||||
|
<xsd:complexType name="CT_Percentage">
|
||||||
|
<xsd:attribute name="val" type="a:ST_Percentage" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_PositiveFixedPercentage">
|
||||||
|
<xsd:attribute name="val" type="a:ST_PositiveFixedPercentage" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_PositivePercentage">
|
||||||
|
<xsd:attribute name="val" type="a:ST_PositivePercentage" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_SchemeColorVal">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="bg1"/>
|
||||||
|
<xsd:enumeration value="tx1"/>
|
||||||
|
<xsd:enumeration value="bg2"/>
|
||||||
|
<xsd:enumeration value="tx2"/>
|
||||||
|
<xsd:enumeration value="accent1"/>
|
||||||
|
<xsd:enumeration value="accent2"/>
|
||||||
|
<xsd:enumeration value="accent3"/>
|
||||||
|
<xsd:enumeration value="accent4"/>
|
||||||
|
<xsd:enumeration value="accent5"/>
|
||||||
|
<xsd:enumeration value="accent6"/>
|
||||||
|
<xsd:enumeration value="hlink"/>
|
||||||
|
<xsd:enumeration value="folHlink"/>
|
||||||
|
<xsd:enumeration value="dk1"/>
|
||||||
|
<xsd:enumeration value="lt1"/>
|
||||||
|
<xsd:enumeration value="dk2"/>
|
||||||
|
<xsd:enumeration value="lt2"/>
|
||||||
|
<xsd:enumeration value="phClr"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_RectAlignment">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="none"/>
|
||||||
|
<xsd:enumeration value="tl"/>
|
||||||
|
<xsd:enumeration value="t"/>
|
||||||
|
<xsd:enumeration value="tr"/>
|
||||||
|
<xsd:enumeration value="l"/>
|
||||||
|
<xsd:enumeration value="ctr"/>
|
||||||
|
<xsd:enumeration value="r"/>
|
||||||
|
<xsd:enumeration value="bl"/>
|
||||||
|
<xsd:enumeration value="b"/>
|
||||||
|
<xsd:enumeration value="br"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_PathShadeType">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="shape"/>
|
||||||
|
<xsd:enumeration value="circle"/>
|
||||||
|
<xsd:enumeration value="rect"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_LineCap">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="rnd"/>
|
||||||
|
<xsd:enumeration value="sq"/>
|
||||||
|
<xsd:enumeration value="flat"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_PresetLineDashVal">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="solid"/>
|
||||||
|
<xsd:enumeration value="dot"/>
|
||||||
|
<xsd:enumeration value="sysDot"/>
|
||||||
|
<xsd:enumeration value="dash"/>
|
||||||
|
<xsd:enumeration value="sysDash"/>
|
||||||
|
<xsd:enumeration value="lgDash"/>
|
||||||
|
<xsd:enumeration value="dashDot"/>
|
||||||
|
<xsd:enumeration value="sysDashDot"/>
|
||||||
|
<xsd:enumeration value="lgDashDot"/>
|
||||||
|
<xsd:enumeration value="lgDashDotDot"/>
|
||||||
|
<xsd:enumeration value="sysDashDotDot"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_PenAlignment">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="ctr"/>
|
||||||
|
<xsd:enumeration value="in"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_CompoundLine">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="sng"/>
|
||||||
|
<xsd:enumeration value="dbl"/>
|
||||||
|
<xsd:enumeration value="thickThin"/>
|
||||||
|
<xsd:enumeration value="thinThick"/>
|
||||||
|
<xsd:enumeration value="tri"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_RelativeRect">
|
||||||
|
<xsd:attribute name="l" use="optional" type="a:ST_Percentage"/>
|
||||||
|
<xsd:attribute name="t" use="optional" type="a:ST_Percentage"/>
|
||||||
|
<xsd:attribute name="r" use="optional" type="a:ST_Percentage"/>
|
||||||
|
<xsd:attribute name="b" use="optional" type="a:ST_Percentage"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:group name="EG_ColorTransform">
|
||||||
|
<xsd:choice>
|
||||||
|
<xsd:element name="tint" type="CT_PositiveFixedPercentage"/>
|
||||||
|
<xsd:element name="shade" type="CT_PositiveFixedPercentage"/>
|
||||||
|
<xsd:element name="alpha" type="CT_PositiveFixedPercentage"/>
|
||||||
|
<xsd:element name="hueMod" type="CT_PositivePercentage"/>
|
||||||
|
<xsd:element name="sat" type="CT_Percentage"/>
|
||||||
|
<xsd:element name="satOff" type="CT_Percentage"/>
|
||||||
|
<xsd:element name="satMod" type="CT_Percentage"/>
|
||||||
|
<xsd:element name="lum" type="CT_Percentage"/>
|
||||||
|
<xsd:element name="lumOff" type="CT_Percentage"/>
|
||||||
|
<xsd:element name="lumMod" type="CT_Percentage"/>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:group>
|
||||||
|
<xsd:complexType name="CT_SRgbColor">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:group ref="EG_ColorTransform" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="val" type="s:ST_HexColorRGB" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_SchemeColor">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:group ref="EG_ColorTransform" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="val" type="ST_SchemeColorVal" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:group name="EG_ColorChoice">
|
||||||
|
<xsd:choice>
|
||||||
|
<xsd:element name="srgbClr" type="CT_SRgbColor"/>
|
||||||
|
<xsd:element name="schemeClr" type="CT_SchemeColor"/>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:group>
|
||||||
|
<xsd:complexType name="CT_Color">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:group ref="EG_ColorChoice"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_GradientStop">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:group ref="EG_ColorChoice"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="pos" type="a:ST_PositiveFixedPercentage" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_GradientStopList">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="gs" type="CT_GradientStop" minOccurs="2" maxOccurs="10"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_LinearShadeProperties">
|
||||||
|
<xsd:attribute name="ang" type="a:ST_PositiveFixedAngle" use="optional"/>
|
||||||
|
<xsd:attribute name="scaled" type="ST_OnOff" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_PathShadeProperties">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="fillToRect" type="CT_RelativeRect" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="path" type="ST_PathShadeType" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:group name="EG_ShadeProperties">
|
||||||
|
<xsd:choice>
|
||||||
|
<xsd:element name="lin" type="CT_LinearShadeProperties"/>
|
||||||
|
<xsd:element name="path" type="CT_PathShadeProperties"/>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:group>
|
||||||
|
<xsd:complexType name="CT_SolidColorFillProperties">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:group ref="EG_ColorChoice" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_GradientFillProperties">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="gsLst" type="CT_GradientStopList" minOccurs="0"/>
|
||||||
|
<xsd:group ref="EG_ShadeProperties" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:group name="EG_FillProperties">
|
||||||
|
<xsd:choice>
|
||||||
|
<xsd:element name="noFill" type="w:CT_Empty"/>
|
||||||
|
<xsd:element name="solidFill" type="CT_SolidColorFillProperties"/>
|
||||||
|
<xsd:element name="gradFill" type="CT_GradientFillProperties"/>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:group>
|
||||||
|
<xsd:complexType name="CT_PresetLineDashProperties">
|
||||||
|
<xsd:attribute name="val" type="ST_PresetLineDashVal" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:group name="EG_LineDashProperties">
|
||||||
|
<xsd:choice>
|
||||||
|
<xsd:element name="prstDash" type="CT_PresetLineDashProperties"/>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:group>
|
||||||
|
<xsd:complexType name="CT_LineJoinMiterProperties">
|
||||||
|
<xsd:attribute name="lim" type="a:ST_PositivePercentage" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:group name="EG_LineJoinProperties">
|
||||||
|
<xsd:choice>
|
||||||
|
<xsd:element name="round" type="w:CT_Empty"/>
|
||||||
|
<xsd:element name="bevel" type="w:CT_Empty"/>
|
||||||
|
<xsd:element name="miter" type="CT_LineJoinMiterProperties"/>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:group>
|
||||||
|
<xsd:simpleType name="ST_PresetCameraType">
|
||||||
|
<xsd:restriction base="xsd:token">
|
||||||
|
<xsd:enumeration value="legacyObliqueTopLeft"/>
|
||||||
|
<xsd:enumeration value="legacyObliqueTop"/>
|
||||||
|
<xsd:enumeration value="legacyObliqueTopRight"/>
|
||||||
|
<xsd:enumeration value="legacyObliqueLeft"/>
|
||||||
|
<xsd:enumeration value="legacyObliqueFront"/>
|
||||||
|
<xsd:enumeration value="legacyObliqueRight"/>
|
||||||
|
<xsd:enumeration value="legacyObliqueBottomLeft"/>
|
||||||
|
<xsd:enumeration value="legacyObliqueBottom"/>
|
||||||
|
<xsd:enumeration value="legacyObliqueBottomRight"/>
|
||||||
|
<xsd:enumeration value="legacyPerspectiveTopLeft"/>
|
||||||
|
<xsd:enumeration value="legacyPerspectiveTop"/>
|
||||||
|
<xsd:enumeration value="legacyPerspectiveTopRight"/>
|
||||||
|
<xsd:enumeration value="legacyPerspectiveLeft"/>
|
||||||
|
<xsd:enumeration value="legacyPerspectiveFront"/>
|
||||||
|
<xsd:enumeration value="legacyPerspectiveRight"/>
|
||||||
|
<xsd:enumeration value="legacyPerspectiveBottomLeft"/>
|
||||||
|
<xsd:enumeration value="legacyPerspectiveBottom"/>
|
||||||
|
<xsd:enumeration value="legacyPerspectiveBottomRight"/>
|
||||||
|
<xsd:enumeration value="orthographicFront"/>
|
||||||
|
<xsd:enumeration value="isometricTopUp"/>
|
||||||
|
<xsd:enumeration value="isometricTopDown"/>
|
||||||
|
<xsd:enumeration value="isometricBottomUp"/>
|
||||||
|
<xsd:enumeration value="isometricBottomDown"/>
|
||||||
|
<xsd:enumeration value="isometricLeftUp"/>
|
||||||
|
<xsd:enumeration value="isometricLeftDown"/>
|
||||||
|
<xsd:enumeration value="isometricRightUp"/>
|
||||||
|
<xsd:enumeration value="isometricRightDown"/>
|
||||||
|
<xsd:enumeration value="isometricOffAxis1Left"/>
|
||||||
|
<xsd:enumeration value="isometricOffAxis1Right"/>
|
||||||
|
<xsd:enumeration value="isometricOffAxis1Top"/>
|
||||||
|
<xsd:enumeration value="isometricOffAxis2Left"/>
|
||||||
|
<xsd:enumeration value="isometricOffAxis2Right"/>
|
||||||
|
<xsd:enumeration value="isometricOffAxis2Top"/>
|
||||||
|
<xsd:enumeration value="isometricOffAxis3Left"/>
|
||||||
|
<xsd:enumeration value="isometricOffAxis3Right"/>
|
||||||
|
<xsd:enumeration value="isometricOffAxis3Bottom"/>
|
||||||
|
<xsd:enumeration value="isometricOffAxis4Left"/>
|
||||||
|
<xsd:enumeration value="isometricOffAxis4Right"/>
|
||||||
|
<xsd:enumeration value="isometricOffAxis4Bottom"/>
|
||||||
|
<xsd:enumeration value="obliqueTopLeft"/>
|
||||||
|
<xsd:enumeration value="obliqueTop"/>
|
||||||
|
<xsd:enumeration value="obliqueTopRight"/>
|
||||||
|
<xsd:enumeration value="obliqueLeft"/>
|
||||||
|
<xsd:enumeration value="obliqueRight"/>
|
||||||
|
<xsd:enumeration value="obliqueBottomLeft"/>
|
||||||
|
<xsd:enumeration value="obliqueBottom"/>
|
||||||
|
<xsd:enumeration value="obliqueBottomRight"/>
|
||||||
|
<xsd:enumeration value="perspectiveFront"/>
|
||||||
|
<xsd:enumeration value="perspectiveLeft"/>
|
||||||
|
<xsd:enumeration value="perspectiveRight"/>
|
||||||
|
<xsd:enumeration value="perspectiveAbove"/>
|
||||||
|
<xsd:enumeration value="perspectiveBelow"/>
|
||||||
|
<xsd:enumeration value="perspectiveAboveLeftFacing"/>
|
||||||
|
<xsd:enumeration value="perspectiveAboveRightFacing"/>
|
||||||
|
<xsd:enumeration value="perspectiveContrastingLeftFacing"/>
|
||||||
|
<xsd:enumeration value="perspectiveContrastingRightFacing"/>
|
||||||
|
<xsd:enumeration value="perspectiveHeroicLeftFacing"/>
|
||||||
|
<xsd:enumeration value="perspectiveHeroicRightFacing"/>
|
||||||
|
<xsd:enumeration value="perspectiveHeroicExtremeLeftFacing"/>
|
||||||
|
<xsd:enumeration value="perspectiveHeroicExtremeRightFacing"/>
|
||||||
|
<xsd:enumeration value="perspectiveRelaxed"/>
|
||||||
|
<xsd:enumeration value="perspectiveRelaxedModerately"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_Camera">
|
||||||
|
<xsd:attribute name="prst" use="required" type="ST_PresetCameraType"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_SphereCoords">
|
||||||
|
<xsd:attribute name="lat" type="a:ST_PositiveFixedAngle" use="required"/>
|
||||||
|
<xsd:attribute name="lon" type="a:ST_PositiveFixedAngle" use="required"/>
|
||||||
|
<xsd:attribute name="rev" type="a:ST_PositiveFixedAngle" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_LightRigType">
|
||||||
|
<xsd:restriction base="xsd:token">
|
||||||
|
<xsd:enumeration value="legacyFlat1"/>
|
||||||
|
<xsd:enumeration value="legacyFlat2"/>
|
||||||
|
<xsd:enumeration value="legacyFlat3"/>
|
||||||
|
<xsd:enumeration value="legacyFlat4"/>
|
||||||
|
<xsd:enumeration value="legacyNormal1"/>
|
||||||
|
<xsd:enumeration value="legacyNormal2"/>
|
||||||
|
<xsd:enumeration value="legacyNormal3"/>
|
||||||
|
<xsd:enumeration value="legacyNormal4"/>
|
||||||
|
<xsd:enumeration value="legacyHarsh1"/>
|
||||||
|
<xsd:enumeration value="legacyHarsh2"/>
|
||||||
|
<xsd:enumeration value="legacyHarsh3"/>
|
||||||
|
<xsd:enumeration value="legacyHarsh4"/>
|
||||||
|
<xsd:enumeration value="threePt"/>
|
||||||
|
<xsd:enumeration value="balanced"/>
|
||||||
|
<xsd:enumeration value="soft"/>
|
||||||
|
<xsd:enumeration value="harsh"/>
|
||||||
|
<xsd:enumeration value="flood"/>
|
||||||
|
<xsd:enumeration value="contrasting"/>
|
||||||
|
<xsd:enumeration value="morning"/>
|
||||||
|
<xsd:enumeration value="sunrise"/>
|
||||||
|
<xsd:enumeration value="sunset"/>
|
||||||
|
<xsd:enumeration value="chilly"/>
|
||||||
|
<xsd:enumeration value="freezing"/>
|
||||||
|
<xsd:enumeration value="flat"/>
|
||||||
|
<xsd:enumeration value="twoPt"/>
|
||||||
|
<xsd:enumeration value="glow"/>
|
||||||
|
<xsd:enumeration value="brightRoom"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_LightRigDirection">
|
||||||
|
<xsd:restriction base="xsd:token">
|
||||||
|
<xsd:enumeration value="tl"/>
|
||||||
|
<xsd:enumeration value="t"/>
|
||||||
|
<xsd:enumeration value="tr"/>
|
||||||
|
<xsd:enumeration value="l"/>
|
||||||
|
<xsd:enumeration value="r"/>
|
||||||
|
<xsd:enumeration value="bl"/>
|
||||||
|
<xsd:enumeration value="b"/>
|
||||||
|
<xsd:enumeration value="br"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_LightRig">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="rot" type="CT_SphereCoords" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="rig" type="ST_LightRigType" use="required"/>
|
||||||
|
<xsd:attribute name="dir" type="ST_LightRigDirection" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_BevelPresetType">
|
||||||
|
<xsd:restriction base="xsd:token">
|
||||||
|
<xsd:enumeration value="relaxedInset"/>
|
||||||
|
<xsd:enumeration value="circle"/>
|
||||||
|
<xsd:enumeration value="slope"/>
|
||||||
|
<xsd:enumeration value="cross"/>
|
||||||
|
<xsd:enumeration value="angle"/>
|
||||||
|
<xsd:enumeration value="softRound"/>
|
||||||
|
<xsd:enumeration value="convex"/>
|
||||||
|
<xsd:enumeration value="coolSlant"/>
|
||||||
|
<xsd:enumeration value="divot"/>
|
||||||
|
<xsd:enumeration value="riblet"/>
|
||||||
|
<xsd:enumeration value="hardEdge"/>
|
||||||
|
<xsd:enumeration value="artDeco"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_Bevel">
|
||||||
|
<xsd:attribute name="w" type="a:ST_PositiveCoordinate" use="optional"/>
|
||||||
|
<xsd:attribute name="h" type="a:ST_PositiveCoordinate" use="optional"/>
|
||||||
|
<xsd:attribute name="prst" type="ST_BevelPresetType" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_PresetMaterialType">
|
||||||
|
<xsd:restriction base="xsd:token">
|
||||||
|
<xsd:enumeration value="legacyMatte"/>
|
||||||
|
<xsd:enumeration value="legacyPlastic"/>
|
||||||
|
<xsd:enumeration value="legacyMetal"/>
|
||||||
|
<xsd:enumeration value="legacyWireframe"/>
|
||||||
|
<xsd:enumeration value="matte"/>
|
||||||
|
<xsd:enumeration value="plastic"/>
|
||||||
|
<xsd:enumeration value="metal"/>
|
||||||
|
<xsd:enumeration value="warmMatte"/>
|
||||||
|
<xsd:enumeration value="translucentPowder"/>
|
||||||
|
<xsd:enumeration value="powder"/>
|
||||||
|
<xsd:enumeration value="dkEdge"/>
|
||||||
|
<xsd:enumeration value="softEdge"/>
|
||||||
|
<xsd:enumeration value="clear"/>
|
||||||
|
<xsd:enumeration value="flat"/>
|
||||||
|
<xsd:enumeration value="softmetal"/>
|
||||||
|
<xsd:enumeration value="none"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_Glow">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:group ref="EG_ColorChoice"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="rad" use="optional" type="a:ST_PositiveCoordinate"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Shadow">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:group ref="EG_ColorChoice"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="blurRad" use="optional" type="a:ST_PositiveCoordinate"/>
|
||||||
|
<xsd:attribute name="dist" use="optional" type="a:ST_PositiveCoordinate"/>
|
||||||
|
<xsd:attribute name="dir" use="optional" type="a:ST_PositiveFixedAngle"/>
|
||||||
|
<xsd:attribute name="sx" use="optional" type="a:ST_Percentage"/>
|
||||||
|
<xsd:attribute name="sy" use="optional" type="a:ST_Percentage"/>
|
||||||
|
<xsd:attribute name="kx" use="optional" type="a:ST_FixedAngle"/>
|
||||||
|
<xsd:attribute name="ky" use="optional" type="a:ST_FixedAngle"/>
|
||||||
|
<xsd:attribute name="algn" use="optional" type="ST_RectAlignment"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Reflection">
|
||||||
|
<xsd:attribute name="blurRad" use="optional" type="a:ST_PositiveCoordinate"/>
|
||||||
|
<xsd:attribute name="stA" use="optional" type="a:ST_PositiveFixedPercentage"/>
|
||||||
|
<xsd:attribute name="stPos" use="optional" type="a:ST_PositiveFixedPercentage"/>
|
||||||
|
<xsd:attribute name="endA" use="optional" type="a:ST_PositiveFixedPercentage"/>
|
||||||
|
<xsd:attribute name="endPos" use="optional" type="a:ST_PositiveFixedPercentage"/>
|
||||||
|
<xsd:attribute name="dist" use="optional" type="a:ST_PositiveCoordinate"/>
|
||||||
|
<xsd:attribute name="dir" use="optional" type="a:ST_PositiveFixedAngle"/>
|
||||||
|
<xsd:attribute name="fadeDir" use="optional" type="a:ST_PositiveFixedAngle"/>
|
||||||
|
<xsd:attribute name="sx" use="optional" type="a:ST_Percentage"/>
|
||||||
|
<xsd:attribute name="sy" use="optional" type="a:ST_Percentage"/>
|
||||||
|
<xsd:attribute name="kx" use="optional" type="a:ST_FixedAngle"/>
|
||||||
|
<xsd:attribute name="ky" use="optional" type="a:ST_FixedAngle"/>
|
||||||
|
<xsd:attribute name="algn" use="optional" type="ST_RectAlignment"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_FillTextEffect">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:group ref="EG_FillProperties" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_TextOutlineEffect">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:group ref="EG_FillProperties" minOccurs="0"/>
|
||||||
|
<xsd:group ref="EG_LineDashProperties" minOccurs="0"/>
|
||||||
|
<xsd:group ref="EG_LineJoinProperties" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="w" use="optional" type="a:ST_LineWidth"/>
|
||||||
|
<xsd:attribute name="cap" use="optional" type="ST_LineCap"/>
|
||||||
|
<xsd:attribute name="cmpd" use="optional" type="ST_CompoundLine"/>
|
||||||
|
<xsd:attribute name="algn" use="optional" type="ST_PenAlignment"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Scene3D">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="camera" type="CT_Camera"/>
|
||||||
|
<xsd:element name="lightRig" type="CT_LightRig"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Props3D">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="bevelT" type="CT_Bevel" minOccurs="0"/>
|
||||||
|
<xsd:element name="bevelB" type="CT_Bevel" minOccurs="0"/>
|
||||||
|
<xsd:element name="extrusionClr" type="CT_Color" minOccurs="0"/>
|
||||||
|
<xsd:element name="contourClr" type="CT_Color" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="extrusionH" type="a:ST_PositiveCoordinate" use="optional"/>
|
||||||
|
<xsd:attribute name="contourW" type="a:ST_PositiveCoordinate" use="optional"/>
|
||||||
|
<xsd:attribute name="prstMaterial" type="ST_PresetMaterialType" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:group name="EG_RPrTextEffects">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="glow" minOccurs="0" type="CT_Glow"/>
|
||||||
|
<xsd:element name="shadow" minOccurs="0" type="CT_Shadow"/>
|
||||||
|
<xsd:element name="reflection" minOccurs="0" type="CT_Reflection"/>
|
||||||
|
<xsd:element name="textOutline" minOccurs="0" type="CT_TextOutlineEffect"/>
|
||||||
|
<xsd:element name="textFill" minOccurs="0" type="CT_FillTextEffect"/>
|
||||||
|
<xsd:element name="scene3d" minOccurs="0" type="CT_Scene3D"/>
|
||||||
|
<xsd:element name="props3d" minOccurs="0" type="CT_Props3D"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:group>
|
||||||
|
<xsd:simpleType name="ST_Ligatures">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="none"/>
|
||||||
|
<xsd:enumeration value="standard"/>
|
||||||
|
<xsd:enumeration value="contextual"/>
|
||||||
|
<xsd:enumeration value="historical"/>
|
||||||
|
<xsd:enumeration value="discretional"/>
|
||||||
|
<xsd:enumeration value="standardContextual"/>
|
||||||
|
<xsd:enumeration value="standardHistorical"/>
|
||||||
|
<xsd:enumeration value="contextualHistorical"/>
|
||||||
|
<xsd:enumeration value="standardDiscretional"/>
|
||||||
|
<xsd:enumeration value="contextualDiscretional"/>
|
||||||
|
<xsd:enumeration value="historicalDiscretional"/>
|
||||||
|
<xsd:enumeration value="standardContextualHistorical"/>
|
||||||
|
<xsd:enumeration value="standardContextualDiscretional"/>
|
||||||
|
<xsd:enumeration value="standardHistoricalDiscretional"/>
|
||||||
|
<xsd:enumeration value="contextualHistoricalDiscretional"/>
|
||||||
|
<xsd:enumeration value="all"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_Ligatures">
|
||||||
|
<xsd:attribute name="val" type="ST_Ligatures" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_NumForm">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="default"/>
|
||||||
|
<xsd:enumeration value="lining"/>
|
||||||
|
<xsd:enumeration value="oldStyle"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_NumForm">
|
||||||
|
<xsd:attribute name="val" type="ST_NumForm" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_NumSpacing">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="default"/>
|
||||||
|
<xsd:enumeration value="proportional"/>
|
||||||
|
<xsd:enumeration value="tabular"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_NumSpacing">
|
||||||
|
<xsd:attribute name="val" type="ST_NumSpacing" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_StyleSet">
|
||||||
|
<xsd:attribute name="id" type="s:ST_UnsignedDecimalNumber" use="required"/>
|
||||||
|
<xsd:attribute name="val" type="ST_OnOff" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_StylisticSets">
|
||||||
|
<xsd:sequence minOccurs="0">
|
||||||
|
<xsd:element name="styleSet" minOccurs="0" maxOccurs="unbounded" type="CT_StyleSet"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:group name="EG_RPrOpenType">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="ligatures" minOccurs="0" type="CT_Ligatures"/>
|
||||||
|
<xsd:element name="numForm" minOccurs="0" type="CT_NumForm"/>
|
||||||
|
<xsd:element name="numSpacing" minOccurs="0" type="CT_NumSpacing"/>
|
||||||
|
<xsd:element name="stylisticSets" minOccurs="0" type="CT_StylisticSets"/>
|
||||||
|
<xsd:element name="cntxtAlts" minOccurs="0" type="CT_OnOff"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:group>
|
||||||
|
<xsd:element name="discardImageEditingData" type="CT_OnOff"/>
|
||||||
|
<xsd:element name="defaultImageDpi" type="CT_DefaultImageDpi"/>
|
||||||
|
<xsd:complexType name="CT_DefaultImageDpi">
|
||||||
|
<xsd:attribute name="val" type="w:ST_DecimalNumber" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:element name="entityPicker" type="w:CT_Empty"/>
|
||||||
|
<xsd:complexType name="CT_SdtCheckboxSymbol">
|
||||||
|
<xsd:attribute name="font" type="s:ST_String"/>
|
||||||
|
<xsd:attribute name="val" type="w:ST_ShortHexNumber"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_SdtCheckbox">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="checked" type="CT_OnOff" minOccurs="0"/>
|
||||||
|
<xsd:element name="checkedState" type="CT_SdtCheckboxSymbol" minOccurs="0"/>
|
||||||
|
<xsd:element name="uncheckedState" type="CT_SdtCheckboxSymbol" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:element name="checkbox" type="CT_SdtCheckbox"/>
|
||||||
|
</xsd:schema>
|
||||||
@ -0,0 +1,67 @@
|
|||||||
|
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:w12="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" elementFormDefault="qualified" attributeFormDefault="qualified" blockDefault="#all" xmlns="http://schemas.microsoft.com/office/word/2012/wordml" targetNamespace="http://schemas.microsoft.com/office/word/2012/wordml">
|
||||||
|
<xsd:import id="w12" namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main" schemaLocation="../ISO-IEC29500-4_2016/wml.xsd"/>
|
||||||
|
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" schemaLocation="../ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd"/>
|
||||||
|
<xsd:element name="color" type="w12:CT_Color"/>
|
||||||
|
<xsd:simpleType name="ST_SdtAppearance">
|
||||||
|
<xsd:restriction base="xsd:string">
|
||||||
|
<xsd:enumeration value="boundingBox"/>
|
||||||
|
<xsd:enumeration value="tags"/>
|
||||||
|
<xsd:enumeration value="hidden"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:element name="dataBinding" type="w12:CT_DataBinding"/>
|
||||||
|
<xsd:complexType name="CT_SdtAppearance">
|
||||||
|
<xsd:attribute name="val" type="ST_SdtAppearance"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:element name="appearance" type="CT_SdtAppearance"/>
|
||||||
|
<xsd:complexType name="CT_CommentsEx">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="commentEx" type="CT_CommentEx" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_CommentEx">
|
||||||
|
<xsd:attribute name="paraId" type="w12:ST_LongHexNumber" use="required"/>
|
||||||
|
<xsd:attribute name="paraIdParent" type="w12:ST_LongHexNumber" use="optional"/>
|
||||||
|
<xsd:attribute name="done" type="s:ST_OnOff" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:element name="commentsEx" type="CT_CommentsEx"/>
|
||||||
|
<xsd:complexType name="CT_People">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="person" type="CT_Person" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_PresenceInfo">
|
||||||
|
<xsd:attribute name="providerId" type="xsd:string" use="required"/>
|
||||||
|
<xsd:attribute name="userId" type="xsd:string" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Person">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="presenceInfo" type="CT_PresenceInfo" minOccurs="0" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="author" type="s:ST_String" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:element name="people" type="CT_People"/>
|
||||||
|
<xsd:complexType name="CT_SdtRepeatedSection">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="sectionTitle" type="w12:CT_String" minOccurs="0"/>
|
||||||
|
<xsd:element name="doNotAllowInsertDeleteSection" type="w12:CT_OnOff" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_Guid">
|
||||||
|
<xsd:restriction base="xsd:token">
|
||||||
|
<xsd:pattern value="\{[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}\}"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_Guid">
|
||||||
|
<xsd:attribute name="val" type="ST_Guid"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:element name="repeatingSection" type="CT_SdtRepeatedSection"/>
|
||||||
|
<xsd:element name="repeatingSectionItem" type="w12:CT_Empty"/>
|
||||||
|
<xsd:element name="chartTrackingRefBased" type="w12:CT_OnOff"/>
|
||||||
|
<xsd:element name="collapsed" type="w12:CT_OnOff"/>
|
||||||
|
<xsd:element name="docId" type="CT_Guid"/>
|
||||||
|
<xsd:element name="footnoteColumns" type="w12:CT_DecimalNumber"/>
|
||||||
|
<xsd:element name="webExtensionLinked" type="w12:CT_OnOff"/>
|
||||||
|
<xsd:element name="webExtensionCreated" type="w12:CT_OnOff"/>
|
||||||
|
<xsd:attribute name="restartNumberingAfterBreak" type="s:ST_OnOff"/>
|
||||||
|
</xsd:schema>
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:w12="http://schemas.openxmlformats.org/wordprocessingml/2006/main" elementFormDefault="qualified" attributeFormDefault="qualified" blockDefault="#all" xmlns="http://schemas.microsoft.com/office/word/2018/wordml" targetNamespace="http://schemas.microsoft.com/office/word/2018/wordml">
|
||||||
|
<xsd:import id="w12" namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main" schemaLocation="../ISO-IEC29500-4_2016/wml.xsd"/>
|
||||||
|
<xsd:complexType name="CT_Extension">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:any processContents="lax"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="uri" type="xsd:token"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_ExtensionList">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="ext" type="CT_Extension" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:schema>
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" xmlns:w16="http://schemas.microsoft.com/office/word/2018/wordml" elementFormDefault="qualified" attributeFormDefault="qualified" blockDefault="#all" xmlns="http://schemas.microsoft.com/office/word/2018/wordml/cex" targetNamespace="http://schemas.microsoft.com/office/word/2018/wordml/cex">
|
||||||
|
<xsd:import id="w16" namespace="http://schemas.microsoft.com/office/word/2018/wordml" schemaLocation="wml-2018.xsd"/>
|
||||||
|
<xsd:import id="w" namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main" schemaLocation="../ISO-IEC29500-4_2016/wml.xsd"/>
|
||||||
|
<xsd:import id="s" namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes" schemaLocation="../ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd"/>
|
||||||
|
<xsd:complexType name="CT_CommentsExtensible">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="commentExtensible" type="CT_CommentExtensible" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
<xsd:element name="extLst" type="w16:CT_ExtensionList" minOccurs="0" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_CommentExtensible">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="extLst" type="w16:CT_ExtensionList" minOccurs="0" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="durableId" type="w:ST_LongHexNumber" use="required"/>
|
||||||
|
<xsd:attribute name="dateUtc" type="w:ST_DateTime" use="optional"/>
|
||||||
|
<xsd:attribute name="intelligentPlaceholder" type="s:ST_OnOff" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:element name="commentsExtensible" type="CT_CommentsExtensible"/>
|
||||||
|
</xsd:schema>
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:w12="http://schemas.openxmlformats.org/wordprocessingml/2006/main" elementFormDefault="qualified" attributeFormDefault="qualified" blockDefault="#all" xmlns="http://schemas.microsoft.com/office/word/2016/wordml/cid" targetNamespace="http://schemas.microsoft.com/office/word/2016/wordml/cid">
|
||||||
|
<xsd:import id="w12" namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main" schemaLocation="../ISO-IEC29500-4_2016/wml.xsd"/>
|
||||||
|
<xsd:complexType name="CT_CommentsIds">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="commentId" type="CT_CommentId" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_CommentId">
|
||||||
|
<xsd:attribute name="paraId" type="w12:ST_LongHexNumber" use="required"/>
|
||||||
|
<xsd:attribute name="durableId" type="w12:ST_LongHexNumber" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:element name="commentsIds" type="CT_CommentsIds"/>
|
||||||
|
</xsd:schema>
|
||||||
@ -0,0 +1,4 @@
|
|||||||
|
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:w12="http://schemas.openxmlformats.org/wordprocessingml/2006/main" elementFormDefault="qualified" attributeFormDefault="qualified" blockDefault="#all" xmlns="http://schemas.microsoft.com/office/word/2020/wordml/sdtdatahash" targetNamespace="http://schemas.microsoft.com/office/word/2020/wordml/sdtdatahash">
|
||||||
|
<xsd:import id="w12" namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main" schemaLocation="../ISO-IEC29500-4_2016/wml.xsd"/>
|
||||||
|
<xsd:attribute name="storeItemChecksum" type="w12:ST_String"/>
|
||||||
|
</xsd:schema>
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:w12="http://schemas.openxmlformats.org/wordprocessingml/2006/main" elementFormDefault="qualified" attributeFormDefault="qualified" blockDefault="#all" xmlns="http://schemas.microsoft.com/office/word/2015/wordml/symex" targetNamespace="http://schemas.microsoft.com/office/word/2015/wordml/symex">
|
||||||
|
<xsd:import id="w12" namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main" schemaLocation="../ISO-IEC29500-4_2016/wml.xsd"/>
|
||||||
|
<xsd:complexType name="CT_SymEx">
|
||||||
|
<xsd:attribute name="font" type="w12:ST_String"/>
|
||||||
|
<xsd:attribute name="char" type="w12:ST_LongHexNumber"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:element name="symEx" type="CT_SymEx"/>
|
||||||
|
</xsd:schema>
|
||||||
@ -0,0 +1,220 @@
|
|||||||
|
"""
|
||||||
|
Helper for running LibreOffice (soffice) in environments where AF_UNIX
|
||||||
|
sockets may be blocked (e.g., sandboxed VMs). Detects the restriction
|
||||||
|
at runtime and applies an LD_PRELOAD shim if needed.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
from office.soffice import run_soffice, get_soffice_cmd, get_soffice_env
|
||||||
|
|
||||||
|
# Option 1 – run soffice directly
|
||||||
|
result = run_soffice(["--headless", "--convert-to", "pdf", "input.docx"])
|
||||||
|
|
||||||
|
# Option 2 – get env dict for your own subprocess calls
|
||||||
|
env = get_soffice_env()
|
||||||
|
subprocess.run([get_soffice_cmd(), ...], env=env)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import platform
|
||||||
|
import shutil
|
||||||
|
import socket
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def get_soffice_cmd() -> str:
|
||||||
|
"""Return the soffice command name for the current platform."""
|
||||||
|
# Prefer PATH first on all platforms.
|
||||||
|
path_cmd = shutil.which("soffice")
|
||||||
|
if path_cmd:
|
||||||
|
return path_cmd
|
||||||
|
|
||||||
|
if platform.system() == "Windows":
|
||||||
|
# Windows can expose soffice as .com or .exe; try both on PATH first.
|
||||||
|
for candidate_name in ("soffice.com", "soffice.exe"):
|
||||||
|
path_candidate = shutil.which(candidate_name)
|
||||||
|
if path_candidate:
|
||||||
|
return path_candidate
|
||||||
|
|
||||||
|
# On Windows, try to find soffice.exe via common install paths
|
||||||
|
for prog_dir in (
|
||||||
|
os.environ.get("PROGRAMFILES", r"C:\Program Files"),
|
||||||
|
os.environ.get("PROGRAMFILES(X86)", r"C:\Program Files (x86)"),
|
||||||
|
):
|
||||||
|
if not prog_dir:
|
||||||
|
continue
|
||||||
|
program_dir = Path(prog_dir) / "LibreOffice" / "program"
|
||||||
|
for exe_name in ("soffice.com", "soffice.exe"):
|
||||||
|
candidate = program_dir / exe_name
|
||||||
|
if candidate.exists():
|
||||||
|
return str(candidate)
|
||||||
|
return "soffice" # fallback, hope it's on PATH
|
||||||
|
return "soffice"
|
||||||
|
|
||||||
|
|
||||||
|
def get_soffice_env() -> dict:
|
||||||
|
env = os.environ.copy()
|
||||||
|
# SAL_USE_VCLPLUGIN=svp is Linux-only (headless rendering)
|
||||||
|
if platform.system() == "Linux":
|
||||||
|
env["SAL_USE_VCLPLUGIN"] = "svp"
|
||||||
|
|
||||||
|
if _needs_shim():
|
||||||
|
shim = _ensure_shim()
|
||||||
|
env["LD_PRELOAD"] = str(shim)
|
||||||
|
|
||||||
|
return env
|
||||||
|
|
||||||
|
|
||||||
|
def run_soffice(args: list[str], **kwargs) -> subprocess.CompletedProcess:
|
||||||
|
env = get_soffice_env()
|
||||||
|
return subprocess.run([get_soffice_cmd()] + args, env=env, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_SHIM_SO = Path(tempfile.gettempdir()) / "lo_socket_shim.so"
|
||||||
|
|
||||||
|
|
||||||
|
def _needs_shim() -> bool:
|
||||||
|
# AF_UNIX / LD_PRELOAD shim is Linux-only; skip on Windows and macOS
|
||||||
|
if not hasattr(socket, "AF_UNIX"):
|
||||||
|
return False
|
||||||
|
try:
|
||||||
|
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
|
s.close()
|
||||||
|
return False
|
||||||
|
except OSError:
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def _ensure_shim() -> Path:
|
||||||
|
if _SHIM_SO.exists():
|
||||||
|
return _SHIM_SO
|
||||||
|
|
||||||
|
src = Path(tempfile.gettempdir()) / "lo_socket_shim.c"
|
||||||
|
src.write_text(_SHIM_SOURCE)
|
||||||
|
subprocess.run(
|
||||||
|
["gcc", "-shared", "-fPIC", "-o", str(_SHIM_SO), str(src), "-ldl"],
|
||||||
|
check=True,
|
||||||
|
capture_output=True,
|
||||||
|
)
|
||||||
|
src.unlink()
|
||||||
|
return _SHIM_SO
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_SHIM_SOURCE = r"""
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
static int (*real_socket)(int, int, int);
|
||||||
|
static int (*real_socketpair)(int, int, int, int[2]);
|
||||||
|
static int (*real_listen)(int, int);
|
||||||
|
static int (*real_accept)(int, struct sockaddr *, socklen_t *);
|
||||||
|
static int (*real_close)(int);
|
||||||
|
static int (*real_read)(int, void *, size_t);
|
||||||
|
|
||||||
|
/* Per-FD bookkeeping (FDs >= 1024 are passed through unshimmed). */
|
||||||
|
static int is_shimmed[1024];
|
||||||
|
static int peer_of[1024];
|
||||||
|
static int wake_r[1024]; /* accept() blocks reading this */
|
||||||
|
static int wake_w[1024]; /* close() writes to this */
|
||||||
|
static int listener_fd = -1; /* FD that received listen() */
|
||||||
|
|
||||||
|
__attribute__((constructor))
|
||||||
|
static void init(void) {
|
||||||
|
real_socket = dlsym(RTLD_NEXT, "socket");
|
||||||
|
real_socketpair = dlsym(RTLD_NEXT, "socketpair");
|
||||||
|
real_listen = dlsym(RTLD_NEXT, "listen");
|
||||||
|
real_accept = dlsym(RTLD_NEXT, "accept");
|
||||||
|
real_close = dlsym(RTLD_NEXT, "close");
|
||||||
|
real_read = dlsym(RTLD_NEXT, "read");
|
||||||
|
for (int i = 0; i < 1024; i++) {
|
||||||
|
peer_of[i] = -1;
|
||||||
|
wake_r[i] = -1;
|
||||||
|
wake_w[i] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- socket ---------------------------------------------------------- */
|
||||||
|
int socket(int domain, int type, int protocol) {
|
||||||
|
if (domain == AF_UNIX) {
|
||||||
|
int fd = real_socket(domain, type, protocol);
|
||||||
|
if (fd >= 0) return fd;
|
||||||
|
/* socket(AF_UNIX) blocked – fall back to socketpair(). */
|
||||||
|
int sv[2];
|
||||||
|
if (real_socketpair(domain, type, protocol, sv) == 0) {
|
||||||
|
if (sv[0] >= 0 && sv[0] < 1024) {
|
||||||
|
is_shimmed[sv[0]] = 1;
|
||||||
|
peer_of[sv[0]] = sv[1];
|
||||||
|
int wp[2];
|
||||||
|
if (pipe(wp) == 0) {
|
||||||
|
wake_r[sv[0]] = wp[0];
|
||||||
|
wake_w[sv[0]] = wp[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sv[0];
|
||||||
|
}
|
||||||
|
errno = EPERM;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return real_socket(domain, type, protocol);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- listen ---------------------------------------------------------- */
|
||||||
|
int listen(int sockfd, int backlog) {
|
||||||
|
if (sockfd >= 0 && sockfd < 1024 && is_shimmed[sockfd]) {
|
||||||
|
listener_fd = sockfd;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return real_listen(sockfd, backlog);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- accept ---------------------------------------------------------- */
|
||||||
|
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
|
||||||
|
if (sockfd >= 0 && sockfd < 1024 && is_shimmed[sockfd]) {
|
||||||
|
/* Block until close() writes to the wake pipe. */
|
||||||
|
if (wake_r[sockfd] >= 0) {
|
||||||
|
char buf;
|
||||||
|
real_read(wake_r[sockfd], &buf, 1);
|
||||||
|
}
|
||||||
|
errno = ECONNABORTED;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return real_accept(sockfd, addr, addrlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---- close ----------------------------------------------------------- */
|
||||||
|
int close(int fd) {
|
||||||
|
if (fd >= 0 && fd < 1024 && is_shimmed[fd]) {
|
||||||
|
int was_listener = (fd == listener_fd);
|
||||||
|
is_shimmed[fd] = 0;
|
||||||
|
|
||||||
|
if (wake_w[fd] >= 0) { /* unblock accept() */
|
||||||
|
char c = 0;
|
||||||
|
write(wake_w[fd], &c, 1);
|
||||||
|
real_close(wake_w[fd]);
|
||||||
|
wake_w[fd] = -1;
|
||||||
|
}
|
||||||
|
if (wake_r[fd] >= 0) { real_close(wake_r[fd]); wake_r[fd] = -1; }
|
||||||
|
if (peer_of[fd] >= 0) { real_close(peer_of[fd]); peer_of[fd] = -1; }
|
||||||
|
|
||||||
|
if (was_listener)
|
||||||
|
_exit(0); /* conversion done – exit */
|
||||||
|
}
|
||||||
|
return real_close(fd);
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
import sys
|
||||||
|
result = run_soffice(sys.argv[1:])
|
||||||
|
sys.exit(result.returncode)
|
||||||
132
mateclaw-server/src/main/resources/skills/docx/scripts/office/unpack.py
Executable file
132
mateclaw-server/src/main/resources/skills/docx/scripts/office/unpack.py
Executable file
@ -0,0 +1,132 @@
|
|||||||
|
"""Unpack Office files (DOCX, PPTX, XLSX) for editing.
|
||||||
|
|
||||||
|
Extracts the ZIP archive, pretty-prints XML files, and optionally:
|
||||||
|
- Merges adjacent runs with identical formatting (DOCX only)
|
||||||
|
- Simplifies adjacent tracked changes from same author (DOCX only)
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python unpack.py <office_file> <output_dir> [options]
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
python unpack.py document.docx unpacked/
|
||||||
|
python unpack.py presentation.pptx unpacked/
|
||||||
|
python unpack.py document.docx unpacked/ --merge-runs false
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import sys
|
||||||
|
import zipfile
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import defusedxml.minidom
|
||||||
|
|
||||||
|
from helpers.merge_runs import merge_runs as do_merge_runs
|
||||||
|
from helpers.simplify_redlines import simplify_redlines as do_simplify_redlines
|
||||||
|
|
||||||
|
SMART_QUOTE_REPLACEMENTS = {
|
||||||
|
"\u201c": "“",
|
||||||
|
"\u201d": "”",
|
||||||
|
"\u2018": "‘",
|
||||||
|
"\u2019": "’",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def unpack(
|
||||||
|
input_file: str,
|
||||||
|
output_directory: str,
|
||||||
|
merge_runs: bool = True,
|
||||||
|
simplify_redlines: bool = True,
|
||||||
|
) -> tuple[None, str]:
|
||||||
|
input_path = Path(input_file)
|
||||||
|
output_path = Path(output_directory)
|
||||||
|
suffix = input_path.suffix.lower()
|
||||||
|
|
||||||
|
if not input_path.exists():
|
||||||
|
return None, f"Error: {input_file} does not exist"
|
||||||
|
|
||||||
|
if suffix not in {".docx", ".pptx", ".xlsx"}:
|
||||||
|
return None, f"Error: {input_file} must be a .docx, .pptx, or .xlsx file"
|
||||||
|
|
||||||
|
try:
|
||||||
|
output_path.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
with zipfile.ZipFile(input_path, "r") as zf:
|
||||||
|
zf.extractall(output_path)
|
||||||
|
|
||||||
|
xml_files = list(output_path.rglob("*.xml")) + list(output_path.rglob("*.rels"))
|
||||||
|
for xml_file in xml_files:
|
||||||
|
_pretty_print_xml(xml_file)
|
||||||
|
|
||||||
|
message = f"Unpacked {input_file} ({len(xml_files)} XML files)"
|
||||||
|
|
||||||
|
if suffix == ".docx":
|
||||||
|
if simplify_redlines:
|
||||||
|
simplify_count, _ = do_simplify_redlines(str(output_path))
|
||||||
|
message += f", simplified {simplify_count} tracked changes"
|
||||||
|
|
||||||
|
if merge_runs:
|
||||||
|
merge_count, _ = do_merge_runs(str(output_path))
|
||||||
|
message += f", merged {merge_count} runs"
|
||||||
|
|
||||||
|
for xml_file in xml_files:
|
||||||
|
_escape_smart_quotes(xml_file)
|
||||||
|
|
||||||
|
return None, message
|
||||||
|
|
||||||
|
except zipfile.BadZipFile:
|
||||||
|
return None, f"Error: {input_file} is not a valid Office file"
|
||||||
|
except Exception as e:
|
||||||
|
return None, f"Error unpacking: {e}"
|
||||||
|
|
||||||
|
|
||||||
|
def _pretty_print_xml(xml_file: Path) -> None:
|
||||||
|
try:
|
||||||
|
content = xml_file.read_text(encoding="utf-8")
|
||||||
|
dom = defusedxml.minidom.parseString(content)
|
||||||
|
xml_file.write_bytes(dom.toprettyxml(indent=" ", encoding="utf-8"))
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def _escape_smart_quotes(xml_file: Path) -> None:
|
||||||
|
try:
|
||||||
|
content = xml_file.read_text(encoding="utf-8")
|
||||||
|
for char, entity in SMART_QUOTE_REPLACEMENTS.items():
|
||||||
|
content = content.replace(char, entity)
|
||||||
|
xml_file.write_text(content, encoding="utf-8")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="Unpack an Office file (DOCX, PPTX, XLSX) for editing"
|
||||||
|
)
|
||||||
|
parser.add_argument("input_file", help="Office file to unpack")
|
||||||
|
parser.add_argument("output_directory", help="Output directory")
|
||||||
|
parser.add_argument(
|
||||||
|
"--merge-runs",
|
||||||
|
type=lambda x: x.lower() == "true",
|
||||||
|
default=True,
|
||||||
|
metavar="true|false",
|
||||||
|
help="Merge adjacent runs with identical formatting (DOCX only, default: true)",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--simplify-redlines",
|
||||||
|
type=lambda x: x.lower() == "true",
|
||||||
|
default=True,
|
||||||
|
metavar="true|false",
|
||||||
|
help="Merge adjacent tracked changes from same author (DOCX only, default: true)",
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
_, message = unpack(
|
||||||
|
args.input_file,
|
||||||
|
args.output_directory,
|
||||||
|
merge_runs=args.merge_runs,
|
||||||
|
simplify_redlines=args.simplify_redlines,
|
||||||
|
)
|
||||||
|
print(message)
|
||||||
|
|
||||||
|
if "Error" in message:
|
||||||
|
sys.exit(1)
|
||||||
111
mateclaw-server/src/main/resources/skills/docx/scripts/office/validate.py
Executable file
111
mateclaw-server/src/main/resources/skills/docx/scripts/office/validate.py
Executable file
@ -0,0 +1,111 @@
|
|||||||
|
"""
|
||||||
|
Command line tool to validate Office document XML files against XSD schemas and tracked changes.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python validate.py <path> [--original <original_file>] [--auto-repair] [--author NAME]
|
||||||
|
|
||||||
|
The first argument can be either:
|
||||||
|
- An unpacked directory containing the Office document XML files
|
||||||
|
- A packed Office file (.docx/.pptx/.xlsx) which will be unpacked to a temp directory
|
||||||
|
|
||||||
|
Auto-repair fixes:
|
||||||
|
- paraId/durableId values that exceed OOXML limits
|
||||||
|
- Missing xml:space="preserve" on w:t elements with whitespace
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
import zipfile
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from validators import DOCXSchemaValidator, PPTXSchemaValidator, RedliningValidator
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description="Validate Office document XML files")
|
||||||
|
parser.add_argument(
|
||||||
|
"path",
|
||||||
|
help="Path to unpacked directory or packed Office file (.docx/.pptx/.xlsx)",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--original",
|
||||||
|
required=False,
|
||||||
|
default=None,
|
||||||
|
help="Path to original file (.docx/.pptx/.xlsx). If omitted, all XSD errors are reported and redlining validation is skipped.",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-v",
|
||||||
|
"--verbose",
|
||||||
|
action="store_true",
|
||||||
|
help="Enable verbose output",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--auto-repair",
|
||||||
|
action="store_true",
|
||||||
|
help="Automatically repair common issues (hex IDs, whitespace preservation)",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--author",
|
||||||
|
default="Claude",
|
||||||
|
help="Author name for redlining validation (default: Claude)",
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
path = Path(args.path)
|
||||||
|
assert path.exists(), f"Error: {path} does not exist"
|
||||||
|
|
||||||
|
original_file = None
|
||||||
|
if args.original:
|
||||||
|
original_file = Path(args.original)
|
||||||
|
assert original_file.is_file(), f"Error: {original_file} is not a file"
|
||||||
|
assert original_file.suffix.lower() in [".docx", ".pptx", ".xlsx"], (
|
||||||
|
f"Error: {original_file} must be a .docx, .pptx, or .xlsx file"
|
||||||
|
)
|
||||||
|
|
||||||
|
file_extension = (original_file or path).suffix.lower()
|
||||||
|
assert file_extension in [".docx", ".pptx", ".xlsx"], (
|
||||||
|
f"Error: Cannot determine file type from {path}. Use --original or provide a .docx/.pptx/.xlsx file."
|
||||||
|
)
|
||||||
|
|
||||||
|
if path.is_file() and path.suffix.lower() in [".docx", ".pptx", ".xlsx"]:
|
||||||
|
temp_dir = tempfile.mkdtemp()
|
||||||
|
with zipfile.ZipFile(path, "r") as zf:
|
||||||
|
zf.extractall(temp_dir)
|
||||||
|
unpacked_dir = Path(temp_dir)
|
||||||
|
else:
|
||||||
|
assert path.is_dir(), f"Error: {path} is not a directory or Office file"
|
||||||
|
unpacked_dir = path
|
||||||
|
|
||||||
|
match file_extension:
|
||||||
|
case ".docx":
|
||||||
|
validators = [
|
||||||
|
DOCXSchemaValidator(unpacked_dir, original_file, verbose=args.verbose),
|
||||||
|
]
|
||||||
|
if original_file:
|
||||||
|
validators.append(
|
||||||
|
RedliningValidator(unpacked_dir, original_file, verbose=args.verbose, author=args.author)
|
||||||
|
)
|
||||||
|
case ".pptx":
|
||||||
|
validators = [
|
||||||
|
PPTXSchemaValidator(unpacked_dir, original_file, verbose=args.verbose),
|
||||||
|
]
|
||||||
|
case _:
|
||||||
|
print(f"Error: Validation not supported for file type {file_extension}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if args.auto_repair:
|
||||||
|
total_repairs = sum(v.repair() for v in validators)
|
||||||
|
if total_repairs:
|
||||||
|
print(f"Auto-repaired {total_repairs} issue(s)")
|
||||||
|
|
||||||
|
success = all(v.validate() for v in validators)
|
||||||
|
|
||||||
|
if success:
|
||||||
|
print("All validations PASSED!")
|
||||||
|
|
||||||
|
sys.exit(0 if success else 1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
"""
|
||||||
|
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",
|
||||||
|
]
|
||||||
@ -0,0 +1,847 @@
|
|||||||
|
"""
|
||||||
|
Base validator with common validation logic for document files.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import defusedxml.minidom
|
||||||
|
import lxml.etree
|
||||||
|
|
||||||
|
|
||||||
|
class BaseSchemaValidator:
|
||||||
|
|
||||||
|
IGNORED_VALIDATION_ERRORS = [
|
||||||
|
"hyphenationZone",
|
||||||
|
"purl.org/dc/terms",
|
||||||
|
]
|
||||||
|
|
||||||
|
UNIQUE_ID_REQUIREMENTS = {
|
||||||
|
"comment": ("id", "file"),
|
||||||
|
"commentrangestart": ("id", "file"),
|
||||||
|
"commentrangeend": ("id", "file"),
|
||||||
|
"bookmarkstart": ("id", "file"),
|
||||||
|
"bookmarkend": ("id", "file"),
|
||||||
|
"sldid": ("id", "file"),
|
||||||
|
"sldmasterid": ("id", "global"),
|
||||||
|
"sldlayoutid": ("id", "global"),
|
||||||
|
"cm": ("authorid", "file"),
|
||||||
|
"sheet": ("sheetid", "file"),
|
||||||
|
"definedname": ("id", "file"),
|
||||||
|
"cxnsp": ("id", "file"),
|
||||||
|
"sp": ("id", "file"),
|
||||||
|
"pic": ("id", "file"),
|
||||||
|
"grpsp": ("id", "file"),
|
||||||
|
}
|
||||||
|
|
||||||
|
EXCLUDED_ID_CONTAINERS = {
|
||||||
|
"sectionlst",
|
||||||
|
}
|
||||||
|
|
||||||
|
ELEMENT_RELATIONSHIP_TYPES = {}
|
||||||
|
|
||||||
|
SCHEMA_MAPPINGS = {
|
||||||
|
"word": "ISO-IEC29500-4_2016/wml.xsd",
|
||||||
|
"ppt": "ISO-IEC29500-4_2016/pml.xsd",
|
||||||
|
"xl": "ISO-IEC29500-4_2016/sml.xsd",
|
||||||
|
"[Content_Types].xml": "ecma/fouth-edition/opc-contentTypes.xsd",
|
||||||
|
"app.xml": "ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd",
|
||||||
|
"core.xml": "ecma/fouth-edition/opc-coreProperties.xsd",
|
||||||
|
"custom.xml": "ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd",
|
||||||
|
".rels": "ecma/fouth-edition/opc-relationships.xsd",
|
||||||
|
"people.xml": "microsoft/wml-2012.xsd",
|
||||||
|
"commentsIds.xml": "microsoft/wml-cid-2016.xsd",
|
||||||
|
"commentsExtensible.xml": "microsoft/wml-cex-2018.xsd",
|
||||||
|
"commentsExtended.xml": "microsoft/wml-2012.xsd",
|
||||||
|
"chart": "ISO-IEC29500-4_2016/dml-chart.xsd",
|
||||||
|
"theme": "ISO-IEC29500-4_2016/dml-main.xsd",
|
||||||
|
"drawing": "ISO-IEC29500-4_2016/dml-main.xsd",
|
||||||
|
}
|
||||||
|
|
||||||
|
MC_NAMESPACE = "http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
XML_NAMESPACE = "http://www.w3.org/XML/1998/namespace"
|
||||||
|
|
||||||
|
PACKAGE_RELATIONSHIPS_NAMESPACE = (
|
||||||
|
"http://schemas.openxmlformats.org/package/2006/relationships"
|
||||||
|
)
|
||||||
|
OFFICE_RELATIONSHIPS_NAMESPACE = (
|
||||||
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
||||||
|
)
|
||||||
|
CONTENT_TYPES_NAMESPACE = (
|
||||||
|
"http://schemas.openxmlformats.org/package/2006/content-types"
|
||||||
|
)
|
||||||
|
|
||||||
|
MAIN_CONTENT_FOLDERS = {"word", "ppt", "xl"}
|
||||||
|
|
||||||
|
OOXML_NAMESPACES = {
|
||||||
|
"http://schemas.openxmlformats.org/officeDocument/2006/math",
|
||||||
|
"http://schemas.openxmlformats.org/officeDocument/2006/relationships",
|
||||||
|
"http://schemas.openxmlformats.org/schemaLibrary/2006/main",
|
||||||
|
"http://schemas.openxmlformats.org/drawingml/2006/main",
|
||||||
|
"http://schemas.openxmlformats.org/drawingml/2006/chart",
|
||||||
|
"http://schemas.openxmlformats.org/drawingml/2006/chartDrawing",
|
||||||
|
"http://schemas.openxmlformats.org/drawingml/2006/diagram",
|
||||||
|
"http://schemas.openxmlformats.org/drawingml/2006/picture",
|
||||||
|
"http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing",
|
||||||
|
"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing",
|
||||||
|
"http://schemas.openxmlformats.org/wordprocessingml/2006/main",
|
||||||
|
"http://schemas.openxmlformats.org/presentationml/2006/main",
|
||||||
|
"http://schemas.openxmlformats.org/spreadsheetml/2006/main",
|
||||||
|
"http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes",
|
||||||
|
"http://www.w3.org/XML/1998/namespace",
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, unpacked_dir, original_file=None, verbose=False):
|
||||||
|
self.unpacked_dir = Path(unpacked_dir).resolve()
|
||||||
|
self.original_file = Path(original_file) if original_file else None
|
||||||
|
self.verbose = verbose
|
||||||
|
|
||||||
|
self.schemas_dir = Path(__file__).parent.parent / "schemas"
|
||||||
|
|
||||||
|
patterns = ["*.xml", "*.rels"]
|
||||||
|
self.xml_files = [
|
||||||
|
f for pattern in patterns for f in self.unpacked_dir.rglob(pattern)
|
||||||
|
]
|
||||||
|
|
||||||
|
if not self.xml_files:
|
||||||
|
print(f"Warning: No XML files found in {self.unpacked_dir}")
|
||||||
|
|
||||||
|
def validate(self):
|
||||||
|
raise NotImplementedError("Subclasses must implement the validate method")
|
||||||
|
|
||||||
|
def repair(self) -> int:
|
||||||
|
return self.repair_whitespace_preservation()
|
||||||
|
|
||||||
|
def repair_whitespace_preservation(self) -> int:
|
||||||
|
repairs = 0
|
||||||
|
|
||||||
|
for xml_file in self.xml_files:
|
||||||
|
try:
|
||||||
|
content = xml_file.read_text(encoding="utf-8")
|
||||||
|
dom = defusedxml.minidom.parseString(content)
|
||||||
|
modified = False
|
||||||
|
|
||||||
|
for elem in dom.getElementsByTagName("*"):
|
||||||
|
if elem.tagName.endswith(":t") and elem.firstChild:
|
||||||
|
text = elem.firstChild.nodeValue
|
||||||
|
if text and (text.startswith((' ', '\t')) or text.endswith((' ', '\t'))):
|
||||||
|
if elem.getAttribute("xml:space") != "preserve":
|
||||||
|
elem.setAttribute("xml:space", "preserve")
|
||||||
|
text_preview = repr(text[:30]) + "..." if len(text) > 30 else repr(text)
|
||||||
|
print(f" Repaired: {xml_file.name}: Added xml:space='preserve' to {elem.tagName}: {text_preview}")
|
||||||
|
repairs += 1
|
||||||
|
modified = True
|
||||||
|
|
||||||
|
if modified:
|
||||||
|
xml_file.write_bytes(dom.toxml(encoding="UTF-8"))
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return repairs
|
||||||
|
|
||||||
|
def validate_xml(self):
|
||||||
|
errors = []
|
||||||
|
|
||||||
|
for xml_file in self.xml_files:
|
||||||
|
try:
|
||||||
|
lxml.etree.parse(str(xml_file))
|
||||||
|
except lxml.etree.XMLSyntaxError as e:
|
||||||
|
errors.append(
|
||||||
|
f" {xml_file.relative_to(self.unpacked_dir)}: "
|
||||||
|
f"Line {e.lineno}: {e.msg}"
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
errors.append(
|
||||||
|
f" {xml_file.relative_to(self.unpacked_dir)}: "
|
||||||
|
f"Unexpected error: {str(e)}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if errors:
|
||||||
|
print(f"FAILED - Found {len(errors)} XML violations:")
|
||||||
|
for error in errors:
|
||||||
|
print(error)
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
if self.verbose:
|
||||||
|
print("PASSED - All XML files are well-formed")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def validate_namespaces(self):
|
||||||
|
errors = []
|
||||||
|
|
||||||
|
for xml_file in self.xml_files:
|
||||||
|
try:
|
||||||
|
root = lxml.etree.parse(str(xml_file)).getroot()
|
||||||
|
declared = set(root.nsmap.keys()) - {None}
|
||||||
|
|
||||||
|
for attr_val in [
|
||||||
|
v for k, v in root.attrib.items() if k.endswith("Ignorable")
|
||||||
|
]:
|
||||||
|
undeclared = set(attr_val.split()) - declared
|
||||||
|
errors.extend(
|
||||||
|
f" {xml_file.relative_to(self.unpacked_dir)}: "
|
||||||
|
f"Namespace '{ns}' in Ignorable but not declared"
|
||||||
|
for ns in undeclared
|
||||||
|
)
|
||||||
|
except lxml.etree.XMLSyntaxError:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if errors:
|
||||||
|
print(f"FAILED - {len(errors)} namespace issues:")
|
||||||
|
for error in errors:
|
||||||
|
print(error)
|
||||||
|
return False
|
||||||
|
if self.verbose:
|
||||||
|
print("PASSED - All namespace prefixes properly declared")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def validate_unique_ids(self):
|
||||||
|
errors = []
|
||||||
|
global_ids = {}
|
||||||
|
|
||||||
|
for xml_file in self.xml_files:
|
||||||
|
try:
|
||||||
|
root = lxml.etree.parse(str(xml_file)).getroot()
|
||||||
|
file_ids = {}
|
||||||
|
|
||||||
|
mc_elements = root.xpath(
|
||||||
|
".//mc:AlternateContent", namespaces={"mc": self.MC_NAMESPACE}
|
||||||
|
)
|
||||||
|
for elem in mc_elements:
|
||||||
|
elem.getparent().remove(elem)
|
||||||
|
|
||||||
|
for elem in root.iter():
|
||||||
|
tag = (
|
||||||
|
elem.tag.split("}")[-1].lower()
|
||||||
|
if "}" in elem.tag
|
||||||
|
else elem.tag.lower()
|
||||||
|
)
|
||||||
|
|
||||||
|
if tag in self.UNIQUE_ID_REQUIREMENTS:
|
||||||
|
in_excluded_container = any(
|
||||||
|
ancestor.tag.split("}")[-1].lower() in self.EXCLUDED_ID_CONTAINERS
|
||||||
|
for ancestor in elem.iterancestors()
|
||||||
|
)
|
||||||
|
if in_excluded_container:
|
||||||
|
continue
|
||||||
|
|
||||||
|
attr_name, scope = self.UNIQUE_ID_REQUIREMENTS[tag]
|
||||||
|
|
||||||
|
id_value = None
|
||||||
|
for attr, value in elem.attrib.items():
|
||||||
|
attr_local = (
|
||||||
|
attr.split("}")[-1].lower()
|
||||||
|
if "}" in attr
|
||||||
|
else attr.lower()
|
||||||
|
)
|
||||||
|
if attr_local == attr_name:
|
||||||
|
id_value = value
|
||||||
|
break
|
||||||
|
|
||||||
|
if id_value is not None:
|
||||||
|
if scope == "global":
|
||||||
|
if id_value in global_ids:
|
||||||
|
prev_file, prev_line, prev_tag = global_ids[
|
||||||
|
id_value
|
||||||
|
]
|
||||||
|
errors.append(
|
||||||
|
f" {xml_file.relative_to(self.unpacked_dir)}: "
|
||||||
|
f"Line {elem.sourceline}: Global ID '{id_value}' in <{tag}> "
|
||||||
|
f"already used in {prev_file} at line {prev_line} in <{prev_tag}>"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
global_ids[id_value] = (
|
||||||
|
xml_file.relative_to(self.unpacked_dir),
|
||||||
|
elem.sourceline,
|
||||||
|
tag,
|
||||||
|
)
|
||||||
|
elif scope == "file":
|
||||||
|
key = (tag, attr_name)
|
||||||
|
if key not in file_ids:
|
||||||
|
file_ids[key] = {}
|
||||||
|
|
||||||
|
if id_value in file_ids[key]:
|
||||||
|
prev_line = file_ids[key][id_value]
|
||||||
|
errors.append(
|
||||||
|
f" {xml_file.relative_to(self.unpacked_dir)}: "
|
||||||
|
f"Line {elem.sourceline}: Duplicate {attr_name}='{id_value}' in <{tag}> "
|
||||||
|
f"(first occurrence at line {prev_line})"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
file_ids[key][id_value] = elem.sourceline
|
||||||
|
|
||||||
|
except (lxml.etree.XMLSyntaxError, Exception) as e:
|
||||||
|
errors.append(
|
||||||
|
f" {xml_file.relative_to(self.unpacked_dir)}: Error: {e}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if errors:
|
||||||
|
print(f"FAILED - Found {len(errors)} ID uniqueness violations:")
|
||||||
|
for error in errors:
|
||||||
|
print(error)
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
if self.verbose:
|
||||||
|
print("PASSED - All required IDs are unique")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def validate_file_references(self):
|
||||||
|
errors = []
|
||||||
|
|
||||||
|
rels_files = list(self.unpacked_dir.rglob("*.rels"))
|
||||||
|
|
||||||
|
if not rels_files:
|
||||||
|
if self.verbose:
|
||||||
|
print("PASSED - No .rels files found")
|
||||||
|
return True
|
||||||
|
|
||||||
|
all_files = []
|
||||||
|
for file_path in self.unpacked_dir.rglob("*"):
|
||||||
|
if (
|
||||||
|
file_path.is_file()
|
||||||
|
and file_path.name != "[Content_Types].xml"
|
||||||
|
and not file_path.name.endswith(".rels")
|
||||||
|
):
|
||||||
|
all_files.append(file_path.resolve())
|
||||||
|
|
||||||
|
all_referenced_files = set()
|
||||||
|
|
||||||
|
if self.verbose:
|
||||||
|
print(
|
||||||
|
f"Found {len(rels_files)} .rels files and {len(all_files)} target files"
|
||||||
|
)
|
||||||
|
|
||||||
|
for rels_file in rels_files:
|
||||||
|
try:
|
||||||
|
rels_root = lxml.etree.parse(str(rels_file)).getroot()
|
||||||
|
|
||||||
|
rels_dir = rels_file.parent
|
||||||
|
|
||||||
|
referenced_files = set()
|
||||||
|
broken_refs = []
|
||||||
|
|
||||||
|
for rel in rels_root.findall(
|
||||||
|
".//ns:Relationship",
|
||||||
|
namespaces={"ns": self.PACKAGE_RELATIONSHIPS_NAMESPACE},
|
||||||
|
):
|
||||||
|
target = rel.get("Target")
|
||||||
|
if target and not target.startswith(
|
||||||
|
("http", "mailto:")
|
||||||
|
):
|
||||||
|
if target.startswith("/"):
|
||||||
|
target_path = self.unpacked_dir / target.lstrip("/")
|
||||||
|
elif rels_file.name == ".rels":
|
||||||
|
target_path = self.unpacked_dir / target
|
||||||
|
else:
|
||||||
|
base_dir = rels_dir.parent
|
||||||
|
target_path = base_dir / target
|
||||||
|
|
||||||
|
try:
|
||||||
|
target_path = target_path.resolve()
|
||||||
|
if target_path.exists() and target_path.is_file():
|
||||||
|
referenced_files.add(target_path)
|
||||||
|
all_referenced_files.add(target_path)
|
||||||
|
else:
|
||||||
|
broken_refs.append((target, rel.sourceline))
|
||||||
|
except (OSError, ValueError):
|
||||||
|
broken_refs.append((target, rel.sourceline))
|
||||||
|
|
||||||
|
if broken_refs:
|
||||||
|
rel_path = rels_file.relative_to(self.unpacked_dir)
|
||||||
|
for broken_ref, line_num in broken_refs:
|
||||||
|
errors.append(
|
||||||
|
f" {rel_path}: Line {line_num}: Broken reference to {broken_ref}"
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
rel_path = rels_file.relative_to(self.unpacked_dir)
|
||||||
|
errors.append(f" Error parsing {rel_path}: {e}")
|
||||||
|
|
||||||
|
unreferenced_files = set(all_files) - all_referenced_files
|
||||||
|
|
||||||
|
if unreferenced_files:
|
||||||
|
for unref_file in sorted(unreferenced_files):
|
||||||
|
unref_rel_path = unref_file.relative_to(self.unpacked_dir)
|
||||||
|
errors.append(f" Unreferenced file: {unref_rel_path}")
|
||||||
|
|
||||||
|
if errors:
|
||||||
|
print(f"FAILED - Found {len(errors)} relationship validation errors:")
|
||||||
|
for error in errors:
|
||||||
|
print(error)
|
||||||
|
print(
|
||||||
|
"CRITICAL: These errors will cause the document to appear corrupt. "
|
||||||
|
+ "Broken references MUST be fixed, "
|
||||||
|
+ "and unreferenced files MUST be referenced or removed."
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
if self.verbose:
|
||||||
|
print(
|
||||||
|
"PASSED - All references are valid and all files are properly referenced"
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def validate_all_relationship_ids(self):
|
||||||
|
import lxml.etree
|
||||||
|
|
||||||
|
errors = []
|
||||||
|
|
||||||
|
for xml_file in self.xml_files:
|
||||||
|
if xml_file.suffix == ".rels":
|
||||||
|
continue
|
||||||
|
|
||||||
|
rels_dir = xml_file.parent / "_rels"
|
||||||
|
rels_file = rels_dir / f"{xml_file.name}.rels"
|
||||||
|
|
||||||
|
if not rels_file.exists():
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
rels_root = lxml.etree.parse(str(rels_file)).getroot()
|
||||||
|
rid_to_type = {}
|
||||||
|
|
||||||
|
for rel in rels_root.findall(
|
||||||
|
f".//{{{self.PACKAGE_RELATIONSHIPS_NAMESPACE}}}Relationship"
|
||||||
|
):
|
||||||
|
rid = rel.get("Id")
|
||||||
|
rel_type = rel.get("Type", "")
|
||||||
|
if rid:
|
||||||
|
if rid in rid_to_type:
|
||||||
|
rels_rel_path = rels_file.relative_to(self.unpacked_dir)
|
||||||
|
errors.append(
|
||||||
|
f" {rels_rel_path}: Line {rel.sourceline}: "
|
||||||
|
f"Duplicate relationship ID '{rid}' (IDs must be unique)"
|
||||||
|
)
|
||||||
|
type_name = (
|
||||||
|
rel_type.split("/")[-1] if "/" in rel_type else rel_type
|
||||||
|
)
|
||||||
|
rid_to_type[rid] = type_name
|
||||||
|
|
||||||
|
xml_root = lxml.etree.parse(str(xml_file)).getroot()
|
||||||
|
|
||||||
|
r_ns = self.OFFICE_RELATIONSHIPS_NAMESPACE
|
||||||
|
rid_attrs_to_check = ["id", "embed", "link"]
|
||||||
|
for elem in xml_root.iter():
|
||||||
|
for attr_name in rid_attrs_to_check:
|
||||||
|
rid_attr = elem.get(f"{{{r_ns}}}{attr_name}")
|
||||||
|
if not rid_attr:
|
||||||
|
continue
|
||||||
|
xml_rel_path = xml_file.relative_to(self.unpacked_dir)
|
||||||
|
elem_name = (
|
||||||
|
elem.tag.split("}")[-1] if "}" in elem.tag else elem.tag
|
||||||
|
)
|
||||||
|
|
||||||
|
if rid_attr not in rid_to_type:
|
||||||
|
errors.append(
|
||||||
|
f" {xml_rel_path}: Line {elem.sourceline}: "
|
||||||
|
f"<{elem_name}> r:{attr_name} references non-existent relationship '{rid_attr}' "
|
||||||
|
f"(valid IDs: {', '.join(sorted(rid_to_type.keys())[:5])}{'...' if len(rid_to_type) > 5 else ''})"
|
||||||
|
)
|
||||||
|
elif attr_name == "id" and self.ELEMENT_RELATIONSHIP_TYPES:
|
||||||
|
expected_type = self._get_expected_relationship_type(
|
||||||
|
elem_name
|
||||||
|
)
|
||||||
|
if expected_type:
|
||||||
|
actual_type = rid_to_type[rid_attr]
|
||||||
|
if expected_type not in actual_type.lower():
|
||||||
|
errors.append(
|
||||||
|
f" {xml_rel_path}: Line {elem.sourceline}: "
|
||||||
|
f"<{elem_name}> references '{rid_attr}' which points to '{actual_type}' "
|
||||||
|
f"but should point to a '{expected_type}' relationship"
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
xml_rel_path = xml_file.relative_to(self.unpacked_dir)
|
||||||
|
errors.append(f" Error processing {xml_rel_path}: {e}")
|
||||||
|
|
||||||
|
if errors:
|
||||||
|
print(f"FAILED - Found {len(errors)} relationship ID reference errors:")
|
||||||
|
for error in errors:
|
||||||
|
print(error)
|
||||||
|
print("\nThese ID mismatches will cause the document to appear corrupt!")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
if self.verbose:
|
||||||
|
print("PASSED - All relationship ID references are valid")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _get_expected_relationship_type(self, element_name):
|
||||||
|
elem_lower = element_name.lower()
|
||||||
|
|
||||||
|
if elem_lower in self.ELEMENT_RELATIONSHIP_TYPES:
|
||||||
|
return self.ELEMENT_RELATIONSHIP_TYPES[elem_lower]
|
||||||
|
|
||||||
|
if elem_lower.endswith("id") and len(elem_lower) > 2:
|
||||||
|
prefix = elem_lower[:-2]
|
||||||
|
if prefix.endswith("master"):
|
||||||
|
return prefix.lower()
|
||||||
|
elif prefix.endswith("layout"):
|
||||||
|
return prefix.lower()
|
||||||
|
else:
|
||||||
|
if prefix == "sld":
|
||||||
|
return "slide"
|
||||||
|
return prefix.lower()
|
||||||
|
|
||||||
|
if elem_lower.endswith("reference") and len(elem_lower) > 9:
|
||||||
|
prefix = elem_lower[:-9]
|
||||||
|
return prefix.lower()
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def validate_content_types(self):
|
||||||
|
errors = []
|
||||||
|
|
||||||
|
content_types_file = self.unpacked_dir / "[Content_Types].xml"
|
||||||
|
if not content_types_file.exists():
|
||||||
|
print("FAILED - [Content_Types].xml file not found")
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
root = lxml.etree.parse(str(content_types_file)).getroot()
|
||||||
|
declared_parts = set()
|
||||||
|
declared_extensions = set()
|
||||||
|
|
||||||
|
for override in root.findall(
|
||||||
|
f".//{{{self.CONTENT_TYPES_NAMESPACE}}}Override"
|
||||||
|
):
|
||||||
|
part_name = override.get("PartName")
|
||||||
|
if part_name is not None:
|
||||||
|
declared_parts.add(part_name.lstrip("/"))
|
||||||
|
|
||||||
|
for default in root.findall(
|
||||||
|
f".//{{{self.CONTENT_TYPES_NAMESPACE}}}Default"
|
||||||
|
):
|
||||||
|
extension = default.get("Extension")
|
||||||
|
if extension is not None:
|
||||||
|
declared_extensions.add(extension.lower())
|
||||||
|
|
||||||
|
declarable_roots = {
|
||||||
|
"sld",
|
||||||
|
"sldLayout",
|
||||||
|
"sldMaster",
|
||||||
|
"presentation",
|
||||||
|
"document",
|
||||||
|
"workbook",
|
||||||
|
"worksheet",
|
||||||
|
"theme",
|
||||||
|
}
|
||||||
|
|
||||||
|
media_extensions = {
|
||||||
|
"png": "image/png",
|
||||||
|
"jpg": "image/jpeg",
|
||||||
|
"jpeg": "image/jpeg",
|
||||||
|
"gif": "image/gif",
|
||||||
|
"bmp": "image/bmp",
|
||||||
|
"tiff": "image/tiff",
|
||||||
|
"wmf": "image/x-wmf",
|
||||||
|
"emf": "image/x-emf",
|
||||||
|
}
|
||||||
|
|
||||||
|
all_files = list(self.unpacked_dir.rglob("*"))
|
||||||
|
all_files = [f for f in all_files if f.is_file()]
|
||||||
|
|
||||||
|
for xml_file in self.xml_files:
|
||||||
|
path_str = str(xml_file.relative_to(self.unpacked_dir)).replace(
|
||||||
|
"\\", "/"
|
||||||
|
)
|
||||||
|
|
||||||
|
if any(
|
||||||
|
skip in path_str
|
||||||
|
for skip in [".rels", "[Content_Types]", "docProps/", "_rels/"]
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
root_tag = lxml.etree.parse(str(xml_file)).getroot().tag
|
||||||
|
root_name = root_tag.split("}")[-1] if "}" in root_tag else root_tag
|
||||||
|
|
||||||
|
if root_name in declarable_roots and path_str not in declared_parts:
|
||||||
|
errors.append(
|
||||||
|
f" {path_str}: File with <{root_name}> root not declared in [Content_Types].xml"
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
|
||||||
|
for file_path in all_files:
|
||||||
|
if file_path.suffix.lower() in {".xml", ".rels"}:
|
||||||
|
continue
|
||||||
|
if file_path.name == "[Content_Types].xml":
|
||||||
|
continue
|
||||||
|
if "_rels" in file_path.parts or "docProps" in file_path.parts:
|
||||||
|
continue
|
||||||
|
|
||||||
|
extension = file_path.suffix.lstrip(".").lower()
|
||||||
|
if extension and extension not in declared_extensions:
|
||||||
|
if extension in media_extensions:
|
||||||
|
relative_path = file_path.relative_to(self.unpacked_dir)
|
||||||
|
errors.append(
|
||||||
|
f' {relative_path}: File with extension \'{extension}\' not declared in [Content_Types].xml - should add: <Default Extension="{extension}" ContentType="{media_extensions[extension]}"/>'
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
errors.append(f" Error parsing [Content_Types].xml: {e}")
|
||||||
|
|
||||||
|
if errors:
|
||||||
|
print(f"FAILED - Found {len(errors)} content type declaration errors:")
|
||||||
|
for error in errors:
|
||||||
|
print(error)
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
if self.verbose:
|
||||||
|
print(
|
||||||
|
"PASSED - All content files are properly declared in [Content_Types].xml"
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def validate_file_against_xsd(self, xml_file, verbose=False):
|
||||||
|
xml_file = Path(xml_file).resolve()
|
||||||
|
unpacked_dir = self.unpacked_dir.resolve()
|
||||||
|
|
||||||
|
is_valid, current_errors = self._validate_single_file_xsd(
|
||||||
|
xml_file, unpacked_dir
|
||||||
|
)
|
||||||
|
|
||||||
|
if is_valid is None:
|
||||||
|
return None, set()
|
||||||
|
elif is_valid:
|
||||||
|
return True, set()
|
||||||
|
|
||||||
|
original_errors = self._get_original_file_errors(xml_file)
|
||||||
|
|
||||||
|
assert current_errors is not None
|
||||||
|
new_errors = current_errors - original_errors
|
||||||
|
|
||||||
|
new_errors = {
|
||||||
|
e for e in new_errors
|
||||||
|
if not any(pattern in e for pattern in self.IGNORED_VALIDATION_ERRORS)
|
||||||
|
}
|
||||||
|
|
||||||
|
if new_errors:
|
||||||
|
if verbose:
|
||||||
|
relative_path = xml_file.relative_to(unpacked_dir)
|
||||||
|
print(f"FAILED - {relative_path}: {len(new_errors)} new error(s)")
|
||||||
|
for error in list(new_errors)[:3]:
|
||||||
|
truncated = error[:250] + "..." if len(error) > 250 else error
|
||||||
|
print(f" - {truncated}")
|
||||||
|
return False, new_errors
|
||||||
|
else:
|
||||||
|
if verbose:
|
||||||
|
print(
|
||||||
|
f"PASSED - No new errors (original had {len(current_errors)} errors)"
|
||||||
|
)
|
||||||
|
return True, set()
|
||||||
|
|
||||||
|
def validate_against_xsd(self):
|
||||||
|
new_errors = []
|
||||||
|
original_error_count = 0
|
||||||
|
valid_count = 0
|
||||||
|
skipped_count = 0
|
||||||
|
|
||||||
|
for xml_file in self.xml_files:
|
||||||
|
relative_path = str(xml_file.relative_to(self.unpacked_dir))
|
||||||
|
is_valid, new_file_errors = self.validate_file_against_xsd(
|
||||||
|
xml_file, verbose=False
|
||||||
|
)
|
||||||
|
|
||||||
|
if is_valid is None:
|
||||||
|
skipped_count += 1
|
||||||
|
continue
|
||||||
|
elif is_valid and not new_file_errors:
|
||||||
|
valid_count += 1
|
||||||
|
continue
|
||||||
|
elif is_valid:
|
||||||
|
original_error_count += 1
|
||||||
|
valid_count += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
new_errors.append(f" {relative_path}: {len(new_file_errors)} new error(s)")
|
||||||
|
for error in list(new_file_errors)[:3]:
|
||||||
|
new_errors.append(
|
||||||
|
f" - {error[:250]}..." if len(error) > 250 else f" - {error}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.verbose:
|
||||||
|
print(f"Validated {len(self.xml_files)} files:")
|
||||||
|
print(f" - Valid: {valid_count}")
|
||||||
|
print(f" - Skipped (no schema): {skipped_count}")
|
||||||
|
if original_error_count:
|
||||||
|
print(f" - With original errors (ignored): {original_error_count}")
|
||||||
|
print(
|
||||||
|
f" - With NEW errors: {len(new_errors) > 0 and len([e for e in new_errors if not e.startswith(' ')]) or 0}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if new_errors:
|
||||||
|
print("\nFAILED - Found NEW validation errors:")
|
||||||
|
for error in new_errors:
|
||||||
|
print(error)
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
if self.verbose:
|
||||||
|
print("\nPASSED - No new XSD validation errors introduced")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _get_schema_path(self, xml_file):
|
||||||
|
if xml_file.name in self.SCHEMA_MAPPINGS:
|
||||||
|
return self.schemas_dir / self.SCHEMA_MAPPINGS[xml_file.name]
|
||||||
|
|
||||||
|
if xml_file.suffix == ".rels":
|
||||||
|
return self.schemas_dir / self.SCHEMA_MAPPINGS[".rels"]
|
||||||
|
|
||||||
|
if "charts/" in str(xml_file) and xml_file.name.startswith("chart"):
|
||||||
|
return self.schemas_dir / self.SCHEMA_MAPPINGS["chart"]
|
||||||
|
|
||||||
|
if "theme/" in str(xml_file) and xml_file.name.startswith("theme"):
|
||||||
|
return self.schemas_dir / self.SCHEMA_MAPPINGS["theme"]
|
||||||
|
|
||||||
|
if xml_file.parent.name in self.MAIN_CONTENT_FOLDERS:
|
||||||
|
return self.schemas_dir / self.SCHEMA_MAPPINGS[xml_file.parent.name]
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _clean_ignorable_namespaces(self, xml_doc):
|
||||||
|
xml_string = lxml.etree.tostring(xml_doc, encoding="unicode")
|
||||||
|
xml_copy = lxml.etree.fromstring(xml_string)
|
||||||
|
|
||||||
|
for elem in xml_copy.iter():
|
||||||
|
attrs_to_remove = []
|
||||||
|
|
||||||
|
for attr in elem.attrib:
|
||||||
|
if "{" in attr:
|
||||||
|
ns = attr.split("}")[0][1:]
|
||||||
|
if ns not in self.OOXML_NAMESPACES:
|
||||||
|
attrs_to_remove.append(attr)
|
||||||
|
|
||||||
|
for attr in attrs_to_remove:
|
||||||
|
del elem.attrib[attr]
|
||||||
|
|
||||||
|
self._remove_ignorable_elements(xml_copy)
|
||||||
|
|
||||||
|
return lxml.etree.ElementTree(xml_copy)
|
||||||
|
|
||||||
|
def _remove_ignorable_elements(self, root):
|
||||||
|
elements_to_remove = []
|
||||||
|
|
||||||
|
for elem in list(root):
|
||||||
|
if not hasattr(elem, "tag") or callable(elem.tag):
|
||||||
|
continue
|
||||||
|
|
||||||
|
tag_str = str(elem.tag)
|
||||||
|
if tag_str.startswith("{"):
|
||||||
|
ns = tag_str.split("}")[0][1:]
|
||||||
|
if ns not in self.OOXML_NAMESPACES:
|
||||||
|
elements_to_remove.append(elem)
|
||||||
|
continue
|
||||||
|
|
||||||
|
self._remove_ignorable_elements(elem)
|
||||||
|
|
||||||
|
for elem in elements_to_remove:
|
||||||
|
root.remove(elem)
|
||||||
|
|
||||||
|
def _preprocess_for_mc_ignorable(self, xml_doc):
|
||||||
|
root = xml_doc.getroot()
|
||||||
|
|
||||||
|
if f"{{{self.MC_NAMESPACE}}}Ignorable" in root.attrib:
|
||||||
|
del root.attrib[f"{{{self.MC_NAMESPACE}}}Ignorable"]
|
||||||
|
|
||||||
|
return xml_doc
|
||||||
|
|
||||||
|
def _validate_single_file_xsd(self, xml_file, base_path):
|
||||||
|
schema_path = self._get_schema_path(xml_file)
|
||||||
|
if not schema_path:
|
||||||
|
return None, None
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(schema_path, "rb") as xsd_file:
|
||||||
|
parser = lxml.etree.XMLParser()
|
||||||
|
xsd_doc = lxml.etree.parse(
|
||||||
|
xsd_file, parser=parser, base_url=str(schema_path)
|
||||||
|
)
|
||||||
|
schema = lxml.etree.XMLSchema(xsd_doc)
|
||||||
|
|
||||||
|
with open(xml_file, "r") as f:
|
||||||
|
xml_doc = lxml.etree.parse(f)
|
||||||
|
|
||||||
|
xml_doc, _ = self._remove_template_tags_from_text_nodes(xml_doc)
|
||||||
|
xml_doc = self._preprocess_for_mc_ignorable(xml_doc)
|
||||||
|
|
||||||
|
relative_path = xml_file.relative_to(base_path)
|
||||||
|
if (
|
||||||
|
relative_path.parts
|
||||||
|
and relative_path.parts[0] in self.MAIN_CONTENT_FOLDERS
|
||||||
|
):
|
||||||
|
xml_doc = self._clean_ignorable_namespaces(xml_doc)
|
||||||
|
|
||||||
|
if schema.validate(xml_doc):
|
||||||
|
return True, set()
|
||||||
|
else:
|
||||||
|
errors = set()
|
||||||
|
for error in schema.error_log:
|
||||||
|
errors.add(error.message)
|
||||||
|
return False, errors
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
return False, {str(e)}
|
||||||
|
|
||||||
|
def _get_original_file_errors(self, xml_file):
|
||||||
|
if self.original_file is None:
|
||||||
|
return set()
|
||||||
|
|
||||||
|
import tempfile
|
||||||
|
import zipfile
|
||||||
|
|
||||||
|
xml_file = Path(xml_file).resolve()
|
||||||
|
unpacked_dir = self.unpacked_dir.resolve()
|
||||||
|
relative_path = xml_file.relative_to(unpacked_dir)
|
||||||
|
|
||||||
|
with tempfile.TemporaryDirectory() as temp_dir:
|
||||||
|
temp_path = Path(temp_dir)
|
||||||
|
|
||||||
|
with zipfile.ZipFile(self.original_file, "r") as zip_ref:
|
||||||
|
zip_ref.extractall(temp_path)
|
||||||
|
|
||||||
|
original_xml_file = temp_path / relative_path
|
||||||
|
|
||||||
|
if not original_xml_file.exists():
|
||||||
|
return set()
|
||||||
|
|
||||||
|
is_valid, errors = self._validate_single_file_xsd(
|
||||||
|
original_xml_file, temp_path
|
||||||
|
)
|
||||||
|
return errors if errors else set()
|
||||||
|
|
||||||
|
def _remove_template_tags_from_text_nodes(self, xml_doc):
|
||||||
|
warnings = []
|
||||||
|
template_pattern = re.compile(r"\{\{[^}]*\}\}")
|
||||||
|
|
||||||
|
xml_string = lxml.etree.tostring(xml_doc, encoding="unicode")
|
||||||
|
xml_copy = lxml.etree.fromstring(xml_string)
|
||||||
|
|
||||||
|
def process_text_content(text, content_type):
|
||||||
|
if not text:
|
||||||
|
return text
|
||||||
|
matches = list(template_pattern.finditer(text))
|
||||||
|
if matches:
|
||||||
|
for match in matches:
|
||||||
|
warnings.append(
|
||||||
|
f"Found template tag in {content_type}: {match.group()}"
|
||||||
|
)
|
||||||
|
return template_pattern.sub("", text)
|
||||||
|
return text
|
||||||
|
|
||||||
|
for elem in xml_copy.iter():
|
||||||
|
if not hasattr(elem, "tag") or callable(elem.tag):
|
||||||
|
continue
|
||||||
|
tag_str = str(elem.tag)
|
||||||
|
if tag_str.endswith("}t") or tag_str == "t":
|
||||||
|
continue
|
||||||
|
|
||||||
|
elem.text = process_text_content(elem.text, "text content")
|
||||||
|
elem.tail = process_text_content(elem.tail, "tail content")
|
||||||
|
|
||||||
|
return lxml.etree.ElementTree(xml_copy), warnings
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise RuntimeError("This module should not be run directly.")
|
||||||
@ -0,0 +1,447 @@
|
|||||||
|
"""
|
||||||
|
Validator for Word document XML files against XSD schemas.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import random
|
||||||
|
import re
|
||||||
|
import tempfile
|
||||||
|
import zipfile
|
||||||
|
|
||||||
|
import defusedxml.minidom
|
||||||
|
import lxml.etree
|
||||||
|
|
||||||
|
from .base import BaseSchemaValidator
|
||||||
|
|
||||||
|
|
||||||
|
class DOCXSchemaValidator(BaseSchemaValidator):
|
||||||
|
|
||||||
|
WORD_2006_NAMESPACE = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
|
||||||
|
W14_NAMESPACE = "http://schemas.microsoft.com/office/word/2010/wordml"
|
||||||
|
W16CID_NAMESPACE = "http://schemas.microsoft.com/office/word/2016/wordml/cid"
|
||||||
|
|
||||||
|
ELEMENT_RELATIONSHIP_TYPES = {}
|
||||||
|
|
||||||
|
def validate(self):
|
||||||
|
if not self.validate_xml():
|
||||||
|
return False
|
||||||
|
|
||||||
|
all_valid = True
|
||||||
|
if not self.validate_namespaces():
|
||||||
|
all_valid = False
|
||||||
|
|
||||||
|
if not self.validate_unique_ids():
|
||||||
|
all_valid = False
|
||||||
|
|
||||||
|
if not self.validate_file_references():
|
||||||
|
all_valid = False
|
||||||
|
|
||||||
|
if not self.validate_content_types():
|
||||||
|
all_valid = False
|
||||||
|
|
||||||
|
if not self.validate_against_xsd():
|
||||||
|
all_valid = False
|
||||||
|
|
||||||
|
if not self.validate_whitespace_preservation():
|
||||||
|
all_valid = False
|
||||||
|
|
||||||
|
if not self.validate_deletions():
|
||||||
|
all_valid = False
|
||||||
|
|
||||||
|
if not self.validate_insertions():
|
||||||
|
all_valid = False
|
||||||
|
|
||||||
|
if not self.validate_all_relationship_ids():
|
||||||
|
all_valid = False
|
||||||
|
|
||||||
|
if not self.validate_id_constraints():
|
||||||
|
all_valid = False
|
||||||
|
|
||||||
|
if not self.validate_comment_markers():
|
||||||
|
all_valid = False
|
||||||
|
|
||||||
|
self.compare_paragraph_counts()
|
||||||
|
|
||||||
|
return all_valid
|
||||||
|
|
||||||
|
def validate_whitespace_preservation(self):
|
||||||
|
errors = []
|
||||||
|
|
||||||
|
for xml_file in self.xml_files:
|
||||||
|
if xml_file.name != "document.xml":
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
root = lxml.etree.parse(str(xml_file)).getroot()
|
||||||
|
|
||||||
|
for elem in root.iter(f"{{{self.WORD_2006_NAMESPACE}}}t"):
|
||||||
|
if elem.text:
|
||||||
|
text = elem.text
|
||||||
|
if re.search(r"^[ \t\n\r]", text) or re.search(
|
||||||
|
r"[ \t\n\r]$", text
|
||||||
|
):
|
||||||
|
xml_space_attr = f"{{{self.XML_NAMESPACE}}}space"
|
||||||
|
if (
|
||||||
|
xml_space_attr not in elem.attrib
|
||||||
|
or elem.attrib[xml_space_attr] != "preserve"
|
||||||
|
):
|
||||||
|
text_preview = (
|
||||||
|
repr(text)[:50] + "..."
|
||||||
|
if len(repr(text)) > 50
|
||||||
|
else repr(text)
|
||||||
|
)
|
||||||
|
errors.append(
|
||||||
|
f" {xml_file.relative_to(self.unpacked_dir)}: "
|
||||||
|
f"Line {elem.sourceline}: w:t element with whitespace missing xml:space='preserve': {text_preview}"
|
||||||
|
)
|
||||||
|
|
||||||
|
except (lxml.etree.XMLSyntaxError, Exception) as e:
|
||||||
|
errors.append(
|
||||||
|
f" {xml_file.relative_to(self.unpacked_dir)}: Error: {e}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if errors:
|
||||||
|
print(f"FAILED - Found {len(errors)} whitespace preservation violations:")
|
||||||
|
for error in errors:
|
||||||
|
print(error)
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
if self.verbose:
|
||||||
|
print("PASSED - All whitespace is properly preserved")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def validate_deletions(self):
|
||||||
|
errors = []
|
||||||
|
|
||||||
|
for xml_file in self.xml_files:
|
||||||
|
if xml_file.name != "document.xml":
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
root = lxml.etree.parse(str(xml_file)).getroot()
|
||||||
|
namespaces = {"w": self.WORD_2006_NAMESPACE}
|
||||||
|
|
||||||
|
for t_elem in root.xpath(".//w:del//w:t", namespaces=namespaces):
|
||||||
|
if t_elem.text:
|
||||||
|
text_preview = (
|
||||||
|
repr(t_elem.text)[:50] + "..."
|
||||||
|
if len(repr(t_elem.text)) > 50
|
||||||
|
else repr(t_elem.text)
|
||||||
|
)
|
||||||
|
errors.append(
|
||||||
|
f" {xml_file.relative_to(self.unpacked_dir)}: "
|
||||||
|
f"Line {t_elem.sourceline}: <w:t> found within <w:del>: {text_preview}"
|
||||||
|
)
|
||||||
|
|
||||||
|
for instr_elem in root.xpath(
|
||||||
|
".//w:del//w:instrText", namespaces=namespaces
|
||||||
|
):
|
||||||
|
text_preview = (
|
||||||
|
repr(instr_elem.text or "")[:50] + "..."
|
||||||
|
if len(repr(instr_elem.text or "")) > 50
|
||||||
|
else repr(instr_elem.text or "")
|
||||||
|
)
|
||||||
|
errors.append(
|
||||||
|
f" {xml_file.relative_to(self.unpacked_dir)}: "
|
||||||
|
f"Line {instr_elem.sourceline}: <w:instrText> found within <w:del> (use <w:delInstrText>): {text_preview}"
|
||||||
|
)
|
||||||
|
|
||||||
|
except (lxml.etree.XMLSyntaxError, Exception) as e:
|
||||||
|
errors.append(
|
||||||
|
f" {xml_file.relative_to(self.unpacked_dir)}: Error: {e}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if errors:
|
||||||
|
print(f"FAILED - Found {len(errors)} deletion validation violations:")
|
||||||
|
for error in errors:
|
||||||
|
print(error)
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
if self.verbose:
|
||||||
|
print("PASSED - No w:t elements found within w:del elements")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def count_paragraphs_in_unpacked(self):
|
||||||
|
count = 0
|
||||||
|
|
||||||
|
for xml_file in self.xml_files:
|
||||||
|
if xml_file.name != "document.xml":
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
root = lxml.etree.parse(str(xml_file)).getroot()
|
||||||
|
paragraphs = root.findall(f".//{{{self.WORD_2006_NAMESPACE}}}p")
|
||||||
|
count = len(paragraphs)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error counting paragraphs in unpacked document: {e}")
|
||||||
|
|
||||||
|
return count
|
||||||
|
|
||||||
|
def count_paragraphs_in_original(self):
|
||||||
|
original = self.original_file
|
||||||
|
if original is None:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
|
||||||
|
try:
|
||||||
|
with tempfile.TemporaryDirectory() as temp_dir:
|
||||||
|
with zipfile.ZipFile(original, "r") as zip_ref:
|
||||||
|
zip_ref.extractall(temp_dir)
|
||||||
|
|
||||||
|
doc_xml_path = os.path.join(temp_dir, "word", "document.xml")
|
||||||
|
root = lxml.etree.parse(doc_xml_path).getroot()
|
||||||
|
|
||||||
|
paragraphs = root.findall(f".//{{{self.WORD_2006_NAMESPACE}}}p")
|
||||||
|
count = len(paragraphs)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error counting paragraphs in original document: {e}")
|
||||||
|
|
||||||
|
return count
|
||||||
|
|
||||||
|
def validate_insertions(self):
|
||||||
|
errors = []
|
||||||
|
|
||||||
|
for xml_file in self.xml_files:
|
||||||
|
if xml_file.name != "document.xml":
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
root = lxml.etree.parse(str(xml_file)).getroot()
|
||||||
|
namespaces = {"w": self.WORD_2006_NAMESPACE}
|
||||||
|
|
||||||
|
invalid_elements = root.xpath(
|
||||||
|
".//w:ins//w:delText[not(ancestor::w:del)]", namespaces=namespaces
|
||||||
|
)
|
||||||
|
|
||||||
|
for elem in invalid_elements:
|
||||||
|
text_preview = (
|
||||||
|
repr(elem.text or "")[:50] + "..."
|
||||||
|
if len(repr(elem.text or "")) > 50
|
||||||
|
else repr(elem.text or "")
|
||||||
|
)
|
||||||
|
errors.append(
|
||||||
|
f" {xml_file.relative_to(self.unpacked_dir)}: "
|
||||||
|
f"Line {elem.sourceline}: <w:delText> within <w:ins>: {text_preview}"
|
||||||
|
)
|
||||||
|
|
||||||
|
except (lxml.etree.XMLSyntaxError, Exception) as e:
|
||||||
|
errors.append(
|
||||||
|
f" {xml_file.relative_to(self.unpacked_dir)}: Error: {e}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if errors:
|
||||||
|
print(f"FAILED - Found {len(errors)} insertion validation violations:")
|
||||||
|
for error in errors:
|
||||||
|
print(error)
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
if self.verbose:
|
||||||
|
print("PASSED - No w:delText elements within w:ins elements")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def compare_paragraph_counts(self):
|
||||||
|
original_count = self.count_paragraphs_in_original()
|
||||||
|
new_count = self.count_paragraphs_in_unpacked()
|
||||||
|
|
||||||
|
diff = new_count - original_count
|
||||||
|
diff_str = f"+{diff}" if diff > 0 else str(diff)
|
||||||
|
print(f"\nParagraphs: {original_count} → {new_count} ({diff_str})")
|
||||||
|
|
||||||
|
def _parse_id_value(self, val: str, base: int = 16) -> int:
|
||||||
|
return int(val, base)
|
||||||
|
|
||||||
|
def validate_id_constraints(self):
|
||||||
|
errors = []
|
||||||
|
para_id_attr = f"{{{self.W14_NAMESPACE}}}paraId"
|
||||||
|
durable_id_attr = f"{{{self.W16CID_NAMESPACE}}}durableId"
|
||||||
|
|
||||||
|
for xml_file in self.xml_files:
|
||||||
|
try:
|
||||||
|
for elem in lxml.etree.parse(str(xml_file)).iter():
|
||||||
|
if val := elem.get(para_id_attr):
|
||||||
|
if self._parse_id_value(val, base=16) >= 0x80000000:
|
||||||
|
errors.append(
|
||||||
|
f" {xml_file.name}:{elem.sourceline}: paraId={val} >= 0x80000000"
|
||||||
|
)
|
||||||
|
|
||||||
|
if val := elem.get(durable_id_attr):
|
||||||
|
if xml_file.name == "numbering.xml":
|
||||||
|
try:
|
||||||
|
if self._parse_id_value(val, base=10) >= 0x7FFFFFFF:
|
||||||
|
errors.append(
|
||||||
|
f" {xml_file.name}:{elem.sourceline}: "
|
||||||
|
f"durableId={val} >= 0x7FFFFFFF"
|
||||||
|
)
|
||||||
|
except ValueError:
|
||||||
|
errors.append(
|
||||||
|
f" {xml_file.name}:{elem.sourceline}: "
|
||||||
|
f"durableId={val} must be decimal in numbering.xml"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
if self._parse_id_value(val, base=16) >= 0x7FFFFFFF:
|
||||||
|
errors.append(
|
||||||
|
f" {xml_file.name}:{elem.sourceline}: "
|
||||||
|
f"durableId={val} >= 0x7FFFFFFF"
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if errors:
|
||||||
|
print(f"FAILED - {len(errors)} ID constraint violations:")
|
||||||
|
for e in errors:
|
||||||
|
print(e)
|
||||||
|
elif self.verbose:
|
||||||
|
print("PASSED - All paraId/durableId values within constraints")
|
||||||
|
return not errors
|
||||||
|
|
||||||
|
def validate_comment_markers(self):
|
||||||
|
errors = []
|
||||||
|
|
||||||
|
document_xml = None
|
||||||
|
comments_xml = None
|
||||||
|
for xml_file in self.xml_files:
|
||||||
|
if xml_file.name == "document.xml" and "word" in str(xml_file):
|
||||||
|
document_xml = xml_file
|
||||||
|
elif xml_file.name == "comments.xml":
|
||||||
|
comments_xml = xml_file
|
||||||
|
|
||||||
|
if not document_xml:
|
||||||
|
if self.verbose:
|
||||||
|
print("PASSED - No document.xml found (skipping comment validation)")
|
||||||
|
return True
|
||||||
|
|
||||||
|
try:
|
||||||
|
doc_root = lxml.etree.parse(str(document_xml)).getroot()
|
||||||
|
namespaces = {"w": self.WORD_2006_NAMESPACE}
|
||||||
|
|
||||||
|
range_starts = {
|
||||||
|
elem.get(f"{{{self.WORD_2006_NAMESPACE}}}id")
|
||||||
|
for elem in doc_root.xpath(
|
||||||
|
".//w:commentRangeStart", namespaces=namespaces
|
||||||
|
)
|
||||||
|
}
|
||||||
|
range_ends = {
|
||||||
|
elem.get(f"{{{self.WORD_2006_NAMESPACE}}}id")
|
||||||
|
for elem in doc_root.xpath(
|
||||||
|
".//w:commentRangeEnd", namespaces=namespaces
|
||||||
|
)
|
||||||
|
}
|
||||||
|
references = {
|
||||||
|
elem.get(f"{{{self.WORD_2006_NAMESPACE}}}id")
|
||||||
|
for elem in doc_root.xpath(
|
||||||
|
".//w:commentReference", namespaces=namespaces
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
orphaned_ends = range_ends - range_starts
|
||||||
|
for comment_id in sorted(
|
||||||
|
orphaned_ends, key=lambda x: int(x) if x and x.isdigit() else 0
|
||||||
|
):
|
||||||
|
errors.append(
|
||||||
|
f' document.xml: commentRangeEnd id="{comment_id}" has no matching commentRangeStart'
|
||||||
|
)
|
||||||
|
|
||||||
|
orphaned_starts = range_starts - range_ends
|
||||||
|
for comment_id in sorted(
|
||||||
|
orphaned_starts, key=lambda x: int(x) if x and x.isdigit() else 0
|
||||||
|
):
|
||||||
|
errors.append(
|
||||||
|
f' document.xml: commentRangeStart id="{comment_id}" has no matching commentRangeEnd'
|
||||||
|
)
|
||||||
|
|
||||||
|
comment_ids = set()
|
||||||
|
if comments_xml and comments_xml.exists():
|
||||||
|
comments_root = lxml.etree.parse(str(comments_xml)).getroot()
|
||||||
|
comment_ids = {
|
||||||
|
elem.get(f"{{{self.WORD_2006_NAMESPACE}}}id")
|
||||||
|
for elem in comments_root.xpath(
|
||||||
|
".//w:comment", namespaces=namespaces
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
marker_ids = range_starts | range_ends | references
|
||||||
|
invalid_refs = marker_ids - comment_ids
|
||||||
|
for comment_id in sorted(
|
||||||
|
invalid_refs, key=lambda x: int(x) if x and x.isdigit() else 0
|
||||||
|
):
|
||||||
|
if comment_id:
|
||||||
|
errors.append(
|
||||||
|
f' document.xml: marker id="{comment_id}" references non-existent comment'
|
||||||
|
)
|
||||||
|
|
||||||
|
except (lxml.etree.XMLSyntaxError, Exception) as e:
|
||||||
|
errors.append(f" Error parsing XML: {e}")
|
||||||
|
|
||||||
|
if errors:
|
||||||
|
print(f"FAILED - {len(errors)} comment marker violations:")
|
||||||
|
for error in errors:
|
||||||
|
print(error)
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
if self.verbose:
|
||||||
|
print("PASSED - All comment markers properly paired")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def repair(self) -> int:
|
||||||
|
repairs = super().repair()
|
||||||
|
repairs += self.repair_durableId()
|
||||||
|
return repairs
|
||||||
|
|
||||||
|
def repair_durableId(self) -> int:
|
||||||
|
repairs = 0
|
||||||
|
|
||||||
|
for xml_file in self.xml_files:
|
||||||
|
try:
|
||||||
|
content = xml_file.read_text(encoding="utf-8")
|
||||||
|
dom = defusedxml.minidom.parseString(content)
|
||||||
|
modified = False
|
||||||
|
|
||||||
|
for elem in dom.getElementsByTagName("*"):
|
||||||
|
if not elem.hasAttribute("w16cid:durableId"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
durable_id = elem.getAttribute("w16cid:durableId")
|
||||||
|
needs_repair = False
|
||||||
|
|
||||||
|
if xml_file.name == "numbering.xml":
|
||||||
|
try:
|
||||||
|
needs_repair = (
|
||||||
|
self._parse_id_value(durable_id, base=10) >= 0x7FFFFFFF
|
||||||
|
)
|
||||||
|
except ValueError:
|
||||||
|
needs_repair = True
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
needs_repair = (
|
||||||
|
self._parse_id_value(durable_id, base=16) >= 0x7FFFFFFF
|
||||||
|
)
|
||||||
|
except ValueError:
|
||||||
|
needs_repair = True
|
||||||
|
|
||||||
|
if needs_repair:
|
||||||
|
value = random.randint(1, 0x7FFFFFFE)
|
||||||
|
if xml_file.name == "numbering.xml":
|
||||||
|
new_id = str(value)
|
||||||
|
else:
|
||||||
|
new_id = f"{value:08X}"
|
||||||
|
|
||||||
|
elem.setAttribute("w16cid:durableId", new_id)
|
||||||
|
print(
|
||||||
|
f" Repaired: {xml_file.name}: durableId {durable_id} → {new_id}"
|
||||||
|
)
|
||||||
|
repairs += 1
|
||||||
|
modified = True
|
||||||
|
|
||||||
|
if modified:
|
||||||
|
xml_file.write_bytes(dom.toxml(encoding="UTF-8"))
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return repairs
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise RuntimeError("This module should not be run directly.")
|
||||||
@ -0,0 +1,275 @@
|
|||||||
|
"""
|
||||||
|
Validator for PowerPoint presentation XML files against XSD schemas.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
from .base import BaseSchemaValidator
|
||||||
|
|
||||||
|
|
||||||
|
class PPTXSchemaValidator(BaseSchemaValidator):
|
||||||
|
|
||||||
|
PRESENTATIONML_NAMESPACE = (
|
||||||
|
"http://schemas.openxmlformats.org/presentationml/2006/main"
|
||||||
|
)
|
||||||
|
|
||||||
|
ELEMENT_RELATIONSHIP_TYPES = {
|
||||||
|
"sldid": "slide",
|
||||||
|
"sldmasterid": "slidemaster",
|
||||||
|
"notesmasterid": "notesmaster",
|
||||||
|
"sldlayoutid": "slidelayout",
|
||||||
|
"themeid": "theme",
|
||||||
|
"tablestyleid": "tablestyles",
|
||||||
|
}
|
||||||
|
|
||||||
|
def validate(self):
|
||||||
|
if not self.validate_xml():
|
||||||
|
return False
|
||||||
|
|
||||||
|
all_valid = True
|
||||||
|
if not self.validate_namespaces():
|
||||||
|
all_valid = False
|
||||||
|
|
||||||
|
if not self.validate_unique_ids():
|
||||||
|
all_valid = False
|
||||||
|
|
||||||
|
if not self.validate_uuid_ids():
|
||||||
|
all_valid = False
|
||||||
|
|
||||||
|
if not self.validate_file_references():
|
||||||
|
all_valid = False
|
||||||
|
|
||||||
|
if not self.validate_slide_layout_ids():
|
||||||
|
all_valid = False
|
||||||
|
|
||||||
|
if not self.validate_content_types():
|
||||||
|
all_valid = False
|
||||||
|
|
||||||
|
if not self.validate_against_xsd():
|
||||||
|
all_valid = False
|
||||||
|
|
||||||
|
if not self.validate_notes_slide_references():
|
||||||
|
all_valid = False
|
||||||
|
|
||||||
|
if not self.validate_all_relationship_ids():
|
||||||
|
all_valid = False
|
||||||
|
|
||||||
|
if not self.validate_no_duplicate_slide_layouts():
|
||||||
|
all_valid = False
|
||||||
|
|
||||||
|
return all_valid
|
||||||
|
|
||||||
|
def validate_uuid_ids(self):
|
||||||
|
import lxml.etree
|
||||||
|
|
||||||
|
errors = []
|
||||||
|
uuid_pattern = re.compile(
|
||||||
|
r"^[\{\(]?[0-9A-Fa-f]{8}-?[0-9A-Fa-f]{4}-?[0-9A-Fa-f]{4}-?[0-9A-Fa-f]{4}-?[0-9A-Fa-f]{12}[\}\)]?$"
|
||||||
|
)
|
||||||
|
|
||||||
|
for xml_file in self.xml_files:
|
||||||
|
try:
|
||||||
|
root = lxml.etree.parse(str(xml_file)).getroot()
|
||||||
|
|
||||||
|
for elem in root.iter():
|
||||||
|
for attr, value in elem.attrib.items():
|
||||||
|
attr_name = attr.split("}")[-1].lower()
|
||||||
|
if attr_name == "id" or attr_name.endswith("id"):
|
||||||
|
if self._looks_like_uuid(value):
|
||||||
|
if not uuid_pattern.match(value):
|
||||||
|
errors.append(
|
||||||
|
f" {xml_file.relative_to(self.unpacked_dir)}: "
|
||||||
|
f"Line {elem.sourceline}: ID '{value}' appears to be a UUID but contains invalid hex characters"
|
||||||
|
)
|
||||||
|
|
||||||
|
except (lxml.etree.XMLSyntaxError, Exception) as e:
|
||||||
|
errors.append(
|
||||||
|
f" {xml_file.relative_to(self.unpacked_dir)}: Error: {e}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if errors:
|
||||||
|
print(f"FAILED - Found {len(errors)} UUID ID validation errors:")
|
||||||
|
for error in errors:
|
||||||
|
print(error)
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
if self.verbose:
|
||||||
|
print("PASSED - All UUID-like IDs contain valid hex values")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _looks_like_uuid(self, value):
|
||||||
|
clean_value = value.strip("{}()").replace("-", "")
|
||||||
|
return len(clean_value) == 32 and all(c.isalnum() for c in clean_value)
|
||||||
|
|
||||||
|
def validate_slide_layout_ids(self):
|
||||||
|
import lxml.etree
|
||||||
|
|
||||||
|
errors = []
|
||||||
|
|
||||||
|
slide_masters = list(self.unpacked_dir.glob("ppt/slideMasters/*.xml"))
|
||||||
|
|
||||||
|
if not slide_masters:
|
||||||
|
if self.verbose:
|
||||||
|
print("PASSED - No slide masters found")
|
||||||
|
return True
|
||||||
|
|
||||||
|
for slide_master in slide_masters:
|
||||||
|
try:
|
||||||
|
root = lxml.etree.parse(str(slide_master)).getroot()
|
||||||
|
|
||||||
|
rels_file = slide_master.parent / "_rels" / f"{slide_master.name}.rels"
|
||||||
|
|
||||||
|
if not rels_file.exists():
|
||||||
|
errors.append(
|
||||||
|
f" {slide_master.relative_to(self.unpacked_dir)}: "
|
||||||
|
f"Missing relationships file: {rels_file.relative_to(self.unpacked_dir)}"
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
|
rels_root = lxml.etree.parse(str(rels_file)).getroot()
|
||||||
|
|
||||||
|
valid_layout_rids = set()
|
||||||
|
for rel in rels_root.findall(
|
||||||
|
f".//{{{self.PACKAGE_RELATIONSHIPS_NAMESPACE}}}Relationship"
|
||||||
|
):
|
||||||
|
rel_type = rel.get("Type", "")
|
||||||
|
if "slideLayout" in rel_type:
|
||||||
|
valid_layout_rids.add(rel.get("Id"))
|
||||||
|
|
||||||
|
for sld_layout_id in root.findall(
|
||||||
|
f".//{{{self.PRESENTATIONML_NAMESPACE}}}sldLayoutId"
|
||||||
|
):
|
||||||
|
r_id = sld_layout_id.get(
|
||||||
|
f"{{{self.OFFICE_RELATIONSHIPS_NAMESPACE}}}id"
|
||||||
|
)
|
||||||
|
layout_id = sld_layout_id.get("id")
|
||||||
|
|
||||||
|
if r_id and r_id not in valid_layout_rids:
|
||||||
|
errors.append(
|
||||||
|
f" {slide_master.relative_to(self.unpacked_dir)}: "
|
||||||
|
f"Line {sld_layout_id.sourceline}: sldLayoutId with id='{layout_id}' "
|
||||||
|
f"references r:id='{r_id}' which is not found in slide layout relationships"
|
||||||
|
)
|
||||||
|
|
||||||
|
except (lxml.etree.XMLSyntaxError, Exception) as e:
|
||||||
|
errors.append(
|
||||||
|
f" {slide_master.relative_to(self.unpacked_dir)}: Error: {e}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if errors:
|
||||||
|
print(f"FAILED - Found {len(errors)} slide layout ID validation errors:")
|
||||||
|
for error in errors:
|
||||||
|
print(error)
|
||||||
|
print(
|
||||||
|
"Remove invalid references or add missing slide layouts to the relationships file."
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
if self.verbose:
|
||||||
|
print("PASSED - All slide layout IDs reference valid slide layouts")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def validate_no_duplicate_slide_layouts(self):
|
||||||
|
import lxml.etree
|
||||||
|
|
||||||
|
errors = []
|
||||||
|
slide_rels_files = list(self.unpacked_dir.glob("ppt/slides/_rels/*.xml.rels"))
|
||||||
|
|
||||||
|
for rels_file in slide_rels_files:
|
||||||
|
try:
|
||||||
|
root = lxml.etree.parse(str(rels_file)).getroot()
|
||||||
|
|
||||||
|
layout_rels = [
|
||||||
|
rel
|
||||||
|
for rel in root.findall(
|
||||||
|
f".//{{{self.PACKAGE_RELATIONSHIPS_NAMESPACE}}}Relationship"
|
||||||
|
)
|
||||||
|
if "slideLayout" in rel.get("Type", "")
|
||||||
|
]
|
||||||
|
|
||||||
|
if len(layout_rels) > 1:
|
||||||
|
errors.append(
|
||||||
|
f" {rels_file.relative_to(self.unpacked_dir)}: has {len(layout_rels)} slideLayout references"
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
errors.append(
|
||||||
|
f" {rels_file.relative_to(self.unpacked_dir)}: Error: {e}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if errors:
|
||||||
|
print("FAILED - Found slides with duplicate slideLayout references:")
|
||||||
|
for error in errors:
|
||||||
|
print(error)
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
if self.verbose:
|
||||||
|
print("PASSED - All slides have exactly one slideLayout reference")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def validate_notes_slide_references(self):
|
||||||
|
import lxml.etree
|
||||||
|
|
||||||
|
errors = []
|
||||||
|
notes_slide_references = {}
|
||||||
|
|
||||||
|
slide_rels_files = list(self.unpacked_dir.glob("ppt/slides/_rels/*.xml.rels"))
|
||||||
|
|
||||||
|
if not slide_rels_files:
|
||||||
|
if self.verbose:
|
||||||
|
print("PASSED - No slide relationship files found")
|
||||||
|
return True
|
||||||
|
|
||||||
|
for rels_file in slide_rels_files:
|
||||||
|
try:
|
||||||
|
root = lxml.etree.parse(str(rels_file)).getroot()
|
||||||
|
|
||||||
|
for rel in root.findall(
|
||||||
|
f".//{{{self.PACKAGE_RELATIONSHIPS_NAMESPACE}}}Relationship"
|
||||||
|
):
|
||||||
|
rel_type = rel.get("Type", "")
|
||||||
|
if "notesSlide" in rel_type:
|
||||||
|
target = rel.get("Target", "")
|
||||||
|
if target:
|
||||||
|
normalized_target = target.replace("../", "")
|
||||||
|
|
||||||
|
slide_name = rels_file.stem.replace(
|
||||||
|
".xml", ""
|
||||||
|
)
|
||||||
|
|
||||||
|
if normalized_target not in notes_slide_references:
|
||||||
|
notes_slide_references[normalized_target] = []
|
||||||
|
notes_slide_references[normalized_target].append(
|
||||||
|
(slide_name, rels_file)
|
||||||
|
)
|
||||||
|
|
||||||
|
except (lxml.etree.XMLSyntaxError, Exception) as e:
|
||||||
|
errors.append(
|
||||||
|
f" {rels_file.relative_to(self.unpacked_dir)}: Error: {e}"
|
||||||
|
)
|
||||||
|
|
||||||
|
for target, references in notes_slide_references.items():
|
||||||
|
if len(references) > 1:
|
||||||
|
slide_names = [ref[0] for ref in references]
|
||||||
|
errors.append(
|
||||||
|
f" Notes slide '{target}' is referenced by multiple slides: {', '.join(slide_names)}"
|
||||||
|
)
|
||||||
|
for slide_name, rels_file in references:
|
||||||
|
errors.append(f" - {rels_file.relative_to(self.unpacked_dir)}")
|
||||||
|
|
||||||
|
if errors:
|
||||||
|
print(
|
||||||
|
f"FAILED - Found {len([e for e in errors if not e.startswith(' ')])} notes slide reference validation errors:"
|
||||||
|
)
|
||||||
|
for error in errors:
|
||||||
|
print(error)
|
||||||
|
print("Each slide may optionally have its own slide file.")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
if self.verbose:
|
||||||
|
print("PASSED - All notes slide references are unique")
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise RuntimeError("This module should not be run directly.")
|
||||||
@ -0,0 +1,247 @@
|
|||||||
|
"""
|
||||||
|
Validator for tracked changes in Word documents.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
import zipfile
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
class RedliningValidator:
|
||||||
|
|
||||||
|
def __init__(self, unpacked_dir, original_docx, verbose=False, author="Claude"):
|
||||||
|
self.unpacked_dir = Path(unpacked_dir)
|
||||||
|
self.original_docx = Path(original_docx)
|
||||||
|
self.verbose = verbose
|
||||||
|
self.author = author
|
||||||
|
self.namespaces = {
|
||||||
|
"w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main"
|
||||||
|
}
|
||||||
|
|
||||||
|
def repair(self) -> int:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def validate(self):
|
||||||
|
modified_file = self.unpacked_dir / "word" / "document.xml"
|
||||||
|
if not modified_file.exists():
|
||||||
|
print(f"FAILED - Modified document.xml not found at {modified_file}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
tree = ET.parse(modified_file)
|
||||||
|
root = tree.getroot()
|
||||||
|
|
||||||
|
del_elements = root.findall(".//w:del", self.namespaces)
|
||||||
|
ins_elements = root.findall(".//w:ins", self.namespaces)
|
||||||
|
|
||||||
|
author_del_elements = [
|
||||||
|
elem
|
||||||
|
for elem in del_elements
|
||||||
|
if elem.get(f"{{{self.namespaces['w']}}}author") == self.author
|
||||||
|
]
|
||||||
|
author_ins_elements = [
|
||||||
|
elem
|
||||||
|
for elem in ins_elements
|
||||||
|
if elem.get(f"{{{self.namespaces['w']}}}author") == self.author
|
||||||
|
]
|
||||||
|
|
||||||
|
if not author_del_elements and not author_ins_elements:
|
||||||
|
if self.verbose:
|
||||||
|
print(f"PASSED - No tracked changes by {self.author} found.")
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
with tempfile.TemporaryDirectory() as temp_dir:
|
||||||
|
temp_path = Path(temp_dir)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with zipfile.ZipFile(self.original_docx, "r") as zip_ref:
|
||||||
|
zip_ref.extractall(temp_path)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"FAILED - Error unpacking original docx: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
original_file = temp_path / "word" / "document.xml"
|
||||||
|
if not original_file.exists():
|
||||||
|
print(
|
||||||
|
f"FAILED - Original document.xml not found in {self.original_docx}"
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
modified_tree = ET.parse(modified_file)
|
||||||
|
modified_root = modified_tree.getroot()
|
||||||
|
original_tree = ET.parse(original_file)
|
||||||
|
original_root = original_tree.getroot()
|
||||||
|
except ET.ParseError as e:
|
||||||
|
print(f"FAILED - Error parsing XML files: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
self._remove_author_tracked_changes(original_root)
|
||||||
|
self._remove_author_tracked_changes(modified_root)
|
||||||
|
|
||||||
|
modified_text = self._extract_text_content(modified_root)
|
||||||
|
original_text = self._extract_text_content(original_root)
|
||||||
|
|
||||||
|
if modified_text != original_text:
|
||||||
|
error_message = self._generate_detailed_diff(
|
||||||
|
original_text, modified_text
|
||||||
|
)
|
||||||
|
print(error_message)
|
||||||
|
return False
|
||||||
|
|
||||||
|
if self.verbose:
|
||||||
|
print(f"PASSED - All changes by {self.author} are properly tracked")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _generate_detailed_diff(self, original_text, modified_text):
|
||||||
|
error_parts = [
|
||||||
|
f"FAILED - Document text doesn't match after removing {self.author}'s tracked changes",
|
||||||
|
"",
|
||||||
|
"Likely causes:",
|
||||||
|
" 1. Modified text inside another author's <w:ins> or <w:del> tags",
|
||||||
|
" 2. Made edits without proper tracked changes",
|
||||||
|
" 3. Didn't nest <w:del> inside <w:ins> when deleting another's insertion",
|
||||||
|
"",
|
||||||
|
"For pre-redlined documents, use correct patterns:",
|
||||||
|
" - To reject another's INSERTION: Nest <w:del> inside their <w:ins>",
|
||||||
|
" - To restore another's DELETION: Add new <w:ins> AFTER their <w:del>",
|
||||||
|
"",
|
||||||
|
]
|
||||||
|
|
||||||
|
git_diff = self._get_git_word_diff(original_text, modified_text)
|
||||||
|
if git_diff:
|
||||||
|
error_parts.extend(["Differences:", "============", git_diff])
|
||||||
|
else:
|
||||||
|
error_parts.append("Unable to generate word diff (git not available)")
|
||||||
|
|
||||||
|
return "\n".join(error_parts)
|
||||||
|
|
||||||
|
def _get_git_word_diff(self, original_text, modified_text):
|
||||||
|
try:
|
||||||
|
with tempfile.TemporaryDirectory() as temp_dir:
|
||||||
|
temp_path = Path(temp_dir)
|
||||||
|
|
||||||
|
original_file = temp_path / "original.txt"
|
||||||
|
modified_file = temp_path / "modified.txt"
|
||||||
|
|
||||||
|
original_file.write_text(original_text, encoding="utf-8")
|
||||||
|
modified_file.write_text(modified_text, encoding="utf-8")
|
||||||
|
|
||||||
|
result = subprocess.run(
|
||||||
|
[
|
||||||
|
"git",
|
||||||
|
"diff",
|
||||||
|
"--word-diff=plain",
|
||||||
|
"--word-diff-regex=.",
|
||||||
|
"-U0",
|
||||||
|
"--no-index",
|
||||||
|
str(original_file),
|
||||||
|
str(modified_file),
|
||||||
|
],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
if result.stdout.strip():
|
||||||
|
lines = result.stdout.split("\n")
|
||||||
|
content_lines = []
|
||||||
|
in_content = False
|
||||||
|
for line in lines:
|
||||||
|
if line.startswith("@@"):
|
||||||
|
in_content = True
|
||||||
|
continue
|
||||||
|
if in_content and line.strip():
|
||||||
|
content_lines.append(line)
|
||||||
|
|
||||||
|
if content_lines:
|
||||||
|
return "\n".join(content_lines)
|
||||||
|
|
||||||
|
result = subprocess.run(
|
||||||
|
[
|
||||||
|
"git",
|
||||||
|
"diff",
|
||||||
|
"--word-diff=plain",
|
||||||
|
"-U0",
|
||||||
|
"--no-index",
|
||||||
|
str(original_file),
|
||||||
|
str(modified_file),
|
||||||
|
],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
if result.stdout.strip():
|
||||||
|
lines = result.stdout.split("\n")
|
||||||
|
content_lines = []
|
||||||
|
in_content = False
|
||||||
|
for line in lines:
|
||||||
|
if line.startswith("@@"):
|
||||||
|
in_content = True
|
||||||
|
continue
|
||||||
|
if in_content and line.strip():
|
||||||
|
content_lines.append(line)
|
||||||
|
return "\n".join(content_lines)
|
||||||
|
|
||||||
|
except (subprocess.CalledProcessError, FileNotFoundError, Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _remove_author_tracked_changes(self, root):
|
||||||
|
ins_tag = f"{{{self.namespaces['w']}}}ins"
|
||||||
|
del_tag = f"{{{self.namespaces['w']}}}del"
|
||||||
|
author_attr = f"{{{self.namespaces['w']}}}author"
|
||||||
|
|
||||||
|
for parent in root.iter():
|
||||||
|
to_remove = []
|
||||||
|
for child in parent:
|
||||||
|
if child.tag == ins_tag and child.get(author_attr) == self.author:
|
||||||
|
to_remove.append(child)
|
||||||
|
for elem in to_remove:
|
||||||
|
parent.remove(elem)
|
||||||
|
|
||||||
|
deltext_tag = f"{{{self.namespaces['w']}}}delText"
|
||||||
|
t_tag = f"{{{self.namespaces['w']}}}t"
|
||||||
|
|
||||||
|
for parent in root.iter():
|
||||||
|
to_process = []
|
||||||
|
for child in parent:
|
||||||
|
if child.tag == del_tag and child.get(author_attr) == self.author:
|
||||||
|
to_process.append((child, list(parent).index(child)))
|
||||||
|
|
||||||
|
for del_elem, del_index in reversed(to_process):
|
||||||
|
for elem in del_elem.iter():
|
||||||
|
if elem.tag == deltext_tag:
|
||||||
|
elem.tag = t_tag
|
||||||
|
|
||||||
|
for child in reversed(list(del_elem)):
|
||||||
|
parent.insert(del_index, child)
|
||||||
|
parent.remove(del_elem)
|
||||||
|
|
||||||
|
def _extract_text_content(self, root):
|
||||||
|
p_tag = f"{{{self.namespaces['w']}}}p"
|
||||||
|
t_tag = f"{{{self.namespaces['w']}}}t"
|
||||||
|
|
||||||
|
paragraphs = []
|
||||||
|
for p_elem in root.findall(f".//{p_tag}"):
|
||||||
|
text_parts = []
|
||||||
|
for t_elem in p_elem.findall(f".//{t_tag}"):
|
||||||
|
if t_elem.text:
|
||||||
|
text_parts.append(t_elem.text)
|
||||||
|
paragraph_text = "".join(text_parts)
|
||||||
|
if paragraph_text:
|
||||||
|
paragraphs.append(paragraph_text)
|
||||||
|
|
||||||
|
return "\n".join(paragraphs)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise RuntimeError("This module should not be run directly.")
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
<?xml version="1.0" ?>
|
||||||
|
<w:comments xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:cx="http://schemas.microsoft.com/office/drawing/2014/chartex" xmlns:cx1="http://schemas.microsoft.com/office/drawing/2015/9/8/chartex" xmlns:cx2="http://schemas.microsoft.com/office/drawing/2015/10/21/chartex" xmlns:cx3="http://schemas.microsoft.com/office/drawing/2016/5/9/chartex" xmlns:cx4="http://schemas.microsoft.com/office/drawing/2016/5/10/chartex" xmlns:cx5="http://schemas.microsoft.com/office/drawing/2016/5/11/chartex" xmlns:cx6="http://schemas.microsoft.com/office/drawing/2016/5/12/chartex" xmlns:cx7="http://schemas.microsoft.com/office/drawing/2016/5/13/chartex" xmlns:cx8="http://schemas.microsoft.com/office/drawing/2016/5/14/chartex" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:aink="http://schemas.microsoft.com/office/drawing/2016/ink" xmlns:am3d="http://schemas.microsoft.com/office/drawing/2017/model3d" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:oel="http://schemas.microsoft.com/office/2019/extlst" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:w16cex="http://schemas.microsoft.com/office/word/2018/wordml/cex" xmlns:w16cid="http://schemas.microsoft.com/office/word/2016/wordml/cid" xmlns:w16="http://schemas.microsoft.com/office/word/2018/wordml" xmlns:w16du="http://schemas.microsoft.com/office/word/2023/wordml/word16du" xmlns:w16sdtdh="http://schemas.microsoft.com/office/word/2020/wordml/sdtdatahash" xmlns:w16sdtfl="http://schemas.microsoft.com/office/word/2024/wordml/sdtformatlock" xmlns:w16se="http://schemas.microsoft.com/office/word/2015/wordml/symex" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" mc:Ignorable="w14 w15 w16se w16cid w16 w16cex w16sdtdh w16sdtfl w16du wp14">
|
||||||
|
</w:comments>
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
<?xml version="1.0" ?>
|
||||||
|
<w15:commentsEx xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:cx="http://schemas.microsoft.com/office/drawing/2014/chartex" xmlns:cx1="http://schemas.microsoft.com/office/drawing/2015/9/8/chartex" xmlns:cx2="http://schemas.microsoft.com/office/drawing/2015/10/21/chartex" xmlns:cx3="http://schemas.microsoft.com/office/drawing/2016/5/9/chartex" xmlns:cx4="http://schemas.microsoft.com/office/drawing/2016/5/10/chartex" xmlns:cx5="http://schemas.microsoft.com/office/drawing/2016/5/11/chartex" xmlns:cx6="http://schemas.microsoft.com/office/drawing/2016/5/12/chartex" xmlns:cx7="http://schemas.microsoft.com/office/drawing/2016/5/13/chartex" xmlns:cx8="http://schemas.microsoft.com/office/drawing/2016/5/14/chartex" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:aink="http://schemas.microsoft.com/office/drawing/2016/ink" xmlns:am3d="http://schemas.microsoft.com/office/drawing/2017/model3d" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:oel="http://schemas.microsoft.com/office/2019/extlst" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:w16cex="http://schemas.microsoft.com/office/word/2018/wordml/cex" xmlns:w16cid="http://schemas.microsoft.com/office/word/2016/wordml/cid" xmlns:w16="http://schemas.microsoft.com/office/word/2018/wordml" xmlns:w16du="http://schemas.microsoft.com/office/word/2023/wordml/word16du" xmlns:w16sdtdh="http://schemas.microsoft.com/office/word/2020/wordml/sdtdatahash" xmlns:w16sdtfl="http://schemas.microsoft.com/office/word/2024/wordml/sdtformatlock" xmlns:w16se="http://schemas.microsoft.com/office/word/2015/wordml/symex" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" mc:Ignorable="w14 w15 w16se w16cid w16 w16cex w16sdtdh w16sdtfl w16du wp14">
|
||||||
|
</w15:commentsEx>
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
<?xml version="1.0" ?>
|
||||||
|
<w16cex:commentsExtensible xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:cx="http://schemas.microsoft.com/office/drawing/2014/chartex" xmlns:cx1="http://schemas.microsoft.com/office/drawing/2015/9/8/chartex" xmlns:cx2="http://schemas.microsoft.com/office/drawing/2015/10/21/chartex" xmlns:cx3="http://schemas.microsoft.com/office/drawing/2016/5/9/chartex" xmlns:cx4="http://schemas.microsoft.com/office/drawing/2016/5/10/chartex" xmlns:cx5="http://schemas.microsoft.com/office/drawing/2016/5/11/chartex" xmlns:cx6="http://schemas.microsoft.com/office/drawing/2016/5/12/chartex" xmlns:cx7="http://schemas.microsoft.com/office/drawing/2016/5/13/chartex" xmlns:cx8="http://schemas.microsoft.com/office/drawing/2016/5/14/chartex" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:aink="http://schemas.microsoft.com/office/drawing/2016/ink" xmlns:am3d="http://schemas.microsoft.com/office/drawing/2017/model3d" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:oel="http://schemas.microsoft.com/office/2019/extlst" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:w16cex="http://schemas.microsoft.com/office/word/2018/wordml/cex" xmlns:w16cid="http://schemas.microsoft.com/office/word/2016/wordml/cid" xmlns:w16="http://schemas.microsoft.com/office/word/2018/wordml" xmlns:w16du="http://schemas.microsoft.com/office/word/2023/wordml/word16du" xmlns:w16sdtdh="http://schemas.microsoft.com/office/word/2020/wordml/sdtdatahash" xmlns:w16sdtfl="http://schemas.microsoft.com/office/word/2024/wordml/sdtformatlock" xmlns:w16se="http://schemas.microsoft.com/office/word/2015/wordml/symex" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" xmlns:cr="http://schemas.microsoft.com/office/comments/2020/reactions" mc:Ignorable="w14 w15 w16se w16cid w16 w16cex w16sdtdh w16sdtfl cr w16du wp14">
|
||||||
|
</w16cex:commentsExtensible>
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
<?xml version="1.0" ?>
|
||||||
|
<w16cid:commentsIds xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:cx="http://schemas.microsoft.com/office/drawing/2014/chartex" xmlns:cx1="http://schemas.microsoft.com/office/drawing/2015/9/8/chartex" xmlns:cx2="http://schemas.microsoft.com/office/drawing/2015/10/21/chartex" xmlns:cx3="http://schemas.microsoft.com/office/drawing/2016/5/9/chartex" xmlns:cx4="http://schemas.microsoft.com/office/drawing/2016/5/10/chartex" xmlns:cx5="http://schemas.microsoft.com/office/drawing/2016/5/11/chartex" xmlns:cx6="http://schemas.microsoft.com/office/drawing/2016/5/12/chartex" xmlns:cx7="http://schemas.microsoft.com/office/drawing/2016/5/13/chartex" xmlns:cx8="http://schemas.microsoft.com/office/drawing/2016/5/14/chartex" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:aink="http://schemas.microsoft.com/office/drawing/2016/ink" xmlns:am3d="http://schemas.microsoft.com/office/drawing/2017/model3d" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:oel="http://schemas.microsoft.com/office/2019/extlst" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:w16cex="http://schemas.microsoft.com/office/word/2018/wordml/cex" xmlns:w16cid="http://schemas.microsoft.com/office/word/2016/wordml/cid" xmlns:w16="http://schemas.microsoft.com/office/word/2018/wordml" xmlns:w16du="http://schemas.microsoft.com/office/word/2023/wordml/word16du" xmlns:w16sdtdh="http://schemas.microsoft.com/office/word/2020/wordml/sdtdatahash" xmlns:w16sdtfl="http://schemas.microsoft.com/office/word/2024/wordml/sdtformatlock" xmlns:w16se="http://schemas.microsoft.com/office/word/2015/wordml/symex" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" mc:Ignorable="w14 w15 w16se w16cid w16 w16cex w16sdtdh w16sdtfl w16du wp14">
|
||||||
|
</w16cid:commentsIds>
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
<?xml version="1.0" ?>
|
||||||
|
<w15:people xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml">
|
||||||
|
</w15:people>
|
||||||
179
mateclaw-server/src/main/resources/skills/p5js/scripts/export-frames.js
Executable file
179
mateclaw-server/src/main/resources/skills/p5js/scripts/export-frames.js
Executable file
@ -0,0 +1,179 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
/**
|
||||||
|
* p5.js Skill — Headless Frame Export
|
||||||
|
*
|
||||||
|
* Captures frames from a p5.js sketch using Puppeteer (headless Chrome).
|
||||||
|
* Uses noLoop() + redraw() for DETERMINISTIC frame-by-frame control.
|
||||||
|
*
|
||||||
|
* IMPORTANT: Your sketch must call noLoop() in setup() and set
|
||||||
|
* window._p5Ready = true when initialized. This script calls redraw()
|
||||||
|
* for each frame capture, ensuring exact 1:1 correspondence between
|
||||||
|
* frameCount and captured frames.
|
||||||
|
*
|
||||||
|
* If the sketch does NOT set window._p5Ready, the script falls back to
|
||||||
|
* a timed capture mode (less precise, may drop/duplicate frames).
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* node export-frames.js sketch.html [options]
|
||||||
|
*
|
||||||
|
* Options:
|
||||||
|
* --output <dir> Output directory (default: ./frames)
|
||||||
|
* --width <px> Canvas width (default: 1920)
|
||||||
|
* --height <px> Canvas height (default: 1080)
|
||||||
|
* --frames <n> Number of frames to capture (default: 1)
|
||||||
|
* --fps <n> Target FPS for timed fallback mode (default: 30)
|
||||||
|
* --wait <ms> Wait before first capture (default: 2000)
|
||||||
|
* --selector <sel> Canvas CSS selector (default: canvas)
|
||||||
|
*
|
||||||
|
* Examples:
|
||||||
|
* node export-frames.js sketch.html --frames 1 # single PNG
|
||||||
|
* node export-frames.js sketch.html --frames 300 --fps 30 # 10s at 30fps
|
||||||
|
* node export-frames.js sketch.html --width 3840 --height 2160 # 4K still
|
||||||
|
*
|
||||||
|
* Sketch template for deterministic capture:
|
||||||
|
* function setup() {
|
||||||
|
* createCanvas(1920, 1080);
|
||||||
|
* pixelDensity(1);
|
||||||
|
* noLoop(); // REQUIRED for deterministic capture
|
||||||
|
* window._p5Ready = true; // REQUIRED to signal readiness
|
||||||
|
* }
|
||||||
|
* function draw() { ... }
|
||||||
|
*/
|
||||||
|
|
||||||
|
const puppeteer = require('puppeteer');
|
||||||
|
const path = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
// Parse CLI arguments
|
||||||
|
function parseArgs() {
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
const opts = {
|
||||||
|
input: null,
|
||||||
|
output: './frames',
|
||||||
|
width: 1920,
|
||||||
|
height: 1080,
|
||||||
|
frames: 1,
|
||||||
|
fps: 30,
|
||||||
|
wait: 2000,
|
||||||
|
selector: 'canvas',
|
||||||
|
};
|
||||||
|
|
||||||
|
for (let i = 0; i < args.length; i++) {
|
||||||
|
if (args[i].startsWith('--')) {
|
||||||
|
const key = args[i].slice(2);
|
||||||
|
const val = args[i + 1];
|
||||||
|
if (key in opts && val !== undefined) {
|
||||||
|
opts[key] = isNaN(Number(val)) ? val : Number(val);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
} else if (!opts.input) {
|
||||||
|
opts.input = args[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!opts.input) {
|
||||||
|
console.error('Usage: node export-frames.js <sketch.html> [options]');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return opts;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const opts = parseArgs();
|
||||||
|
const inputPath = path.resolve(opts.input);
|
||||||
|
|
||||||
|
if (!fs.existsSync(inputPath)) {
|
||||||
|
console.error(`File not found: ${inputPath}`);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create output directory
|
||||||
|
fs.mkdirSync(opts.output, { recursive: true });
|
||||||
|
|
||||||
|
console.log(`Capturing ${opts.frames} frame(s) from ${opts.input}`);
|
||||||
|
console.log(`Resolution: ${opts.width}x${opts.height}`);
|
||||||
|
console.log(`Output: ${opts.output}/`);
|
||||||
|
|
||||||
|
const browser = await puppeteer.launch({
|
||||||
|
headless: 'new',
|
||||||
|
args: [
|
||||||
|
'--no-sandbox',
|
||||||
|
'--disable-setuid-sandbox',
|
||||||
|
'--disable-gpu',
|
||||||
|
'--disable-dev-shm-usage',
|
||||||
|
'--disable-web-security',
|
||||||
|
'--allow-file-access-from-files',
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const page = await browser.newPage();
|
||||||
|
|
||||||
|
await page.setViewport({
|
||||||
|
width: opts.width,
|
||||||
|
height: opts.height,
|
||||||
|
deviceScaleFactor: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Navigate to sketch
|
||||||
|
const fileUrl = `file://${inputPath}`;
|
||||||
|
await page.goto(fileUrl, { waitUntil: 'networkidle0', timeout: 30000 });
|
||||||
|
|
||||||
|
// Wait for canvas to appear
|
||||||
|
await page.waitForSelector(opts.selector, { timeout: 10000 });
|
||||||
|
|
||||||
|
// Detect capture mode: deterministic (noLoop+redraw) vs timed (fallback)
|
||||||
|
let deterministic = false;
|
||||||
|
try {
|
||||||
|
await page.waitForFunction('window._p5Ready === true', { timeout: 5000 });
|
||||||
|
deterministic = true;
|
||||||
|
console.log(`Mode: deterministic (noLoop + redraw)`);
|
||||||
|
} catch {
|
||||||
|
console.log(`Mode: timed fallback (sketch does not set window._p5Ready)`);
|
||||||
|
console.log(` For frame-perfect capture, add noLoop() and window._p5Ready=true to setup()`);
|
||||||
|
await new Promise(r => setTimeout(r, opts.wait));
|
||||||
|
}
|
||||||
|
|
||||||
|
const startTime = Date.now();
|
||||||
|
|
||||||
|
for (let i = 0; i < opts.frames; i++) {
|
||||||
|
if (deterministic) {
|
||||||
|
// Advance exactly one frame
|
||||||
|
await page.evaluate(() => { redraw(); });
|
||||||
|
// Brief settle time for render to complete
|
||||||
|
await new Promise(r => setTimeout(r, 20));
|
||||||
|
}
|
||||||
|
|
||||||
|
const frameName = `frame-${String(i).padStart(4, '0')}.png`;
|
||||||
|
const framePath = path.join(opts.output, frameName);
|
||||||
|
|
||||||
|
// Capture the canvas element
|
||||||
|
const canvas = await page.$(opts.selector);
|
||||||
|
if (!canvas) {
|
||||||
|
console.error('Canvas element not found');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
await canvas.screenshot({ path: framePath, type: 'png' });
|
||||||
|
|
||||||
|
// Progress
|
||||||
|
if (i % 30 === 0 || i === opts.frames - 1) {
|
||||||
|
const pct = ((i + 1) / opts.frames * 100).toFixed(1);
|
||||||
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
||||||
|
process.stdout.write(`\r Frame ${i + 1}/${opts.frames} (${pct}%) — ${elapsed}s`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// In timed mode, wait between frames
|
||||||
|
if (!deterministic && i < opts.frames - 1) {
|
||||||
|
await new Promise(r => setTimeout(r, 1000 / opts.fps));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('\n Done.');
|
||||||
|
await browser.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch(err => {
|
||||||
|
console.error('Error:', err.message);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
108
mateclaw-server/src/main/resources/skills/p5js/scripts/render.sh
Executable file
108
mateclaw-server/src/main/resources/skills/p5js/scripts/render.sh
Executable file
@ -0,0 +1,108 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# p5.js Skill — Headless Render Pipeline
|
||||||
|
# Renders a p5.js sketch to MP4 video via Puppeteer + ffmpeg
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# bash scripts/render.sh sketch.html output.mp4 [options]
|
||||||
|
#
|
||||||
|
# Options:
|
||||||
|
# --width Canvas width (default: 1920)
|
||||||
|
# --height Canvas height (default: 1080)
|
||||||
|
# --fps Frames per second (default: 30)
|
||||||
|
# --duration Duration in seconds (default: 10)
|
||||||
|
# --quality CRF value 0-51 (default: 18, lower = better)
|
||||||
|
# --frames-only Only export frames, skip MP4 encoding
|
||||||
|
#
|
||||||
|
# Examples:
|
||||||
|
# bash scripts/render.sh sketch.html output.mp4
|
||||||
|
# bash scripts/render.sh sketch.html output.mp4 --duration 30 --fps 60
|
||||||
|
# bash scripts/render.sh sketch.html output.mp4 --width 3840 --height 2160
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Defaults
|
||||||
|
WIDTH=1920
|
||||||
|
HEIGHT=1080
|
||||||
|
FPS=30
|
||||||
|
DURATION=10
|
||||||
|
CRF=18
|
||||||
|
FRAMES_ONLY=false
|
||||||
|
|
||||||
|
# Parse arguments
|
||||||
|
INPUT="${1:?Usage: render.sh <input.html> <output.mp4> [options]}"
|
||||||
|
OUTPUT="${2:?Usage: render.sh <input.html> <output.mp4> [options]}"
|
||||||
|
shift 2
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
--width) WIDTH="$2"; shift 2 ;;
|
||||||
|
--height) HEIGHT="$2"; shift 2 ;;
|
||||||
|
--fps) FPS="$2"; shift 2 ;;
|
||||||
|
--duration) DURATION="$2"; shift 2 ;;
|
||||||
|
--quality) CRF="$2"; shift 2 ;;
|
||||||
|
--frames-only) FRAMES_ONLY=true; shift ;;
|
||||||
|
*) echo "Unknown option: $1"; exit 1 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
TOTAL_FRAMES=$((FPS * DURATION))
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
FRAME_DIR=$(mktemp -d)
|
||||||
|
|
||||||
|
echo "=== p5.js Render Pipeline ==="
|
||||||
|
echo "Input: $INPUT"
|
||||||
|
echo "Output: $OUTPUT"
|
||||||
|
echo "Resolution: ${WIDTH}x${HEIGHT}"
|
||||||
|
echo "FPS: $FPS"
|
||||||
|
echo "Duration: ${DURATION}s (${TOTAL_FRAMES} frames)"
|
||||||
|
echo "Quality: CRF $CRF"
|
||||||
|
echo "Frame dir: $FRAME_DIR"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Check dependencies
|
||||||
|
command -v node >/dev/null 2>&1 || { echo "Error: Node.js required"; exit 1; }
|
||||||
|
if [ "$FRAMES_ONLY" = false ]; then
|
||||||
|
command -v ffmpeg >/dev/null 2>&1 || { echo "Error: ffmpeg required for MP4"; exit 1; }
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Step 1: Capture frames via Puppeteer
|
||||||
|
echo "Step 1/2: Capturing ${TOTAL_FRAMES} frames..."
|
||||||
|
node "$SCRIPT_DIR/export-frames.js" \
|
||||||
|
"$INPUT" \
|
||||||
|
--output "$FRAME_DIR" \
|
||||||
|
--width "$WIDTH" \
|
||||||
|
--height "$HEIGHT" \
|
||||||
|
--frames "$TOTAL_FRAMES" \
|
||||||
|
--fps "$FPS"
|
||||||
|
|
||||||
|
echo "Frames captured to $FRAME_DIR"
|
||||||
|
|
||||||
|
if [ "$FRAMES_ONLY" = true ]; then
|
||||||
|
echo "Frames saved to: $FRAME_DIR"
|
||||||
|
echo "To encode manually:"
|
||||||
|
echo " ffmpeg -framerate $FPS -i $FRAME_DIR/frame-%04d.png -c:v libx264 -crf $CRF -pix_fmt yuv420p $OUTPUT"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Step 2: Encode to MP4
|
||||||
|
echo "Step 2/2: Encoding MP4..."
|
||||||
|
ffmpeg -y \
|
||||||
|
-framerate "$FPS" \
|
||||||
|
-i "$FRAME_DIR/frame-%04d.png" \
|
||||||
|
-c:v libx264 \
|
||||||
|
-preset slow \
|
||||||
|
-crf "$CRF" \
|
||||||
|
-pix_fmt yuv420p \
|
||||||
|
-movflags +faststart \
|
||||||
|
"$OUTPUT" \
|
||||||
|
2>"$FRAME_DIR/ffmpeg.log"
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
rm -rf "$FRAME_DIR"
|
||||||
|
|
||||||
|
# Report
|
||||||
|
FILE_SIZE=$(ls -lh "$OUTPUT" | awk '{print $5}')
|
||||||
|
echo ""
|
||||||
|
echo "=== Done ==="
|
||||||
|
echo "Output: $OUTPUT ($FILE_SIZE)"
|
||||||
|
echo "Duration: ${DURATION}s at ${FPS}fps, ${WIDTH}x${HEIGHT}"
|
||||||
28
mateclaw-server/src/main/resources/skills/p5js/scripts/serve.sh
Executable file
28
mateclaw-server/src/main/resources/skills/p5js/scripts/serve.sh
Executable file
@ -0,0 +1,28 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# p5.js Skill — Local Development Server
|
||||||
|
# Serves the current directory over HTTP for loading local assets (fonts, images)
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# bash scripts/serve.sh [port] [directory]
|
||||||
|
#
|
||||||
|
# Examples:
|
||||||
|
# bash scripts/serve.sh # serve CWD on port 8080
|
||||||
|
# bash scripts/serve.sh 3000 # serve CWD on port 3000
|
||||||
|
# bash scripts/serve.sh 8080 ./my-project # serve specific directory
|
||||||
|
|
||||||
|
PORT="${1:-8080}"
|
||||||
|
DIR="${2:-.}"
|
||||||
|
|
||||||
|
echo "=== p5.js Dev Server ==="
|
||||||
|
echo "Serving: $(cd "$DIR" && pwd)"
|
||||||
|
echo "URL: http://localhost:$PORT"
|
||||||
|
echo "Press Ctrl+C to stop"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
cd "$DIR" && python3 -m http.server "$PORT" 2>/dev/null || {
|
||||||
|
echo "Python3 not found. Trying Node.js..."
|
||||||
|
npx serve -l "$PORT" "$DIR" 2>/dev/null || {
|
||||||
|
echo "Error: Need python3 or npx (Node.js) for local server"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
87
mateclaw-server/src/main/resources/skills/p5js/scripts/setup.sh
Executable file
87
mateclaw-server/src/main/resources/skills/p5js/scripts/setup.sh
Executable file
@ -0,0 +1,87 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# p5.js Skill — Dependency Verification
|
||||||
|
# Run: bash skills/creative/p5js/scripts/setup.sh
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
ok() { echo -e "${GREEN}[OK]${NC} $1"; }
|
||||||
|
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
||||||
|
fail() { echo -e "${RED}[FAIL]${NC} $1"; }
|
||||||
|
|
||||||
|
echo "=== p5.js Skill — Setup Check ==="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Required: Node.js (for Puppeteer headless export)
|
||||||
|
if command -v node &>/dev/null; then
|
||||||
|
NODE_VER=$(node -v)
|
||||||
|
ok "Node.js $NODE_VER"
|
||||||
|
else
|
||||||
|
warn "Node.js not found — optional, needed for headless export"
|
||||||
|
echo " Install: https://nodejs.org/ or 'brew install node'"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Required: npm (for Puppeteer install)
|
||||||
|
if command -v npm &>/dev/null; then
|
||||||
|
NPM_VER=$(npm -v)
|
||||||
|
ok "npm $NPM_VER"
|
||||||
|
else
|
||||||
|
warn "npm not found — optional, needed for headless export"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Optional: Puppeteer
|
||||||
|
if node -e "require('puppeteer')" 2>/dev/null; then
|
||||||
|
ok "Puppeteer installed"
|
||||||
|
else
|
||||||
|
warn "Puppeteer not installed — needed for headless export"
|
||||||
|
echo " Install: npm install puppeteer"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Optional: ffmpeg (for MP4 encoding from frame sequences)
|
||||||
|
if command -v ffmpeg &>/dev/null; then
|
||||||
|
FFMPEG_VER=$(ffmpeg -version 2>&1 | head -1 | awk '{print $3}')
|
||||||
|
ok "ffmpeg $FFMPEG_VER"
|
||||||
|
else
|
||||||
|
warn "ffmpeg not found — needed for MP4 export"
|
||||||
|
echo " Install: brew install ffmpeg (macOS) or apt install ffmpeg (Linux)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Optional: Python3 (for local server)
|
||||||
|
if command -v python3 &>/dev/null; then
|
||||||
|
PY_VER=$(python3 --version 2>&1 | awk '{print $2}')
|
||||||
|
ok "Python $PY_VER (for local server: python3 -m http.server)"
|
||||||
|
else
|
||||||
|
warn "Python3 not found — needed for local file serving"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Browser check (macOS)
|
||||||
|
if [[ "$(uname)" == "Darwin" ]]; then
|
||||||
|
if open -Ra "Google Chrome" 2>/dev/null; then
|
||||||
|
ok "Google Chrome found"
|
||||||
|
elif open -Ra "Safari" 2>/dev/null; then
|
||||||
|
ok "Safari found"
|
||||||
|
else
|
||||||
|
warn "No browser detected"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Core Requirements ==="
|
||||||
|
echo " A modern browser (Chrome/Firefox/Safari/Edge)"
|
||||||
|
echo " p5.js loaded via CDN — no local install needed"
|
||||||
|
echo ""
|
||||||
|
echo "=== Optional (for export) ==="
|
||||||
|
echo " Node.js + Puppeteer — headless frame capture"
|
||||||
|
echo " ffmpeg — frame sequence to MP4"
|
||||||
|
echo " Python3 — local development server"
|
||||||
|
echo ""
|
||||||
|
echo "=== Quick Start ==="
|
||||||
|
echo " 1. Create an HTML file with inline p5.js sketch"
|
||||||
|
echo " 2. Open in browser: open sketch.html"
|
||||||
|
echo " 3. Press 's' to save PNG, 'g' to save GIF"
|
||||||
|
echo ""
|
||||||
|
echo "Setup check complete."
|
||||||
@ -0,0 +1,65 @@
|
|||||||
|
from dataclasses import dataclass
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class RectAndField:
|
||||||
|
rect: list[float]
|
||||||
|
rect_type: str
|
||||||
|
field: dict
|
||||||
|
|
||||||
|
|
||||||
|
def get_bounding_box_messages(fields_json_stream) -> list[str]:
|
||||||
|
messages = []
|
||||||
|
fields = json.load(fields_json_stream)
|
||||||
|
messages.append(f"Read {len(fields['form_fields'])} fields")
|
||||||
|
|
||||||
|
def rects_intersect(r1, r2):
|
||||||
|
disjoint_horizontal = r1[0] >= r2[2] or r1[2] <= r2[0]
|
||||||
|
disjoint_vertical = r1[1] >= r2[3] or r1[3] <= r2[1]
|
||||||
|
return not (disjoint_horizontal or disjoint_vertical)
|
||||||
|
|
||||||
|
rects_and_fields = []
|
||||||
|
for f in fields["form_fields"]:
|
||||||
|
rects_and_fields.append(RectAndField(f["label_bounding_box"], "label", f))
|
||||||
|
rects_and_fields.append(RectAndField(f["entry_bounding_box"], "entry", f))
|
||||||
|
|
||||||
|
has_error = False
|
||||||
|
for i, ri in enumerate(rects_and_fields):
|
||||||
|
for j in range(i + 1, len(rects_and_fields)):
|
||||||
|
rj = rects_and_fields[j]
|
||||||
|
if ri.field["page_number"] == rj.field["page_number"] and rects_intersect(ri.rect, rj.rect):
|
||||||
|
has_error = True
|
||||||
|
if ri.field is rj.field:
|
||||||
|
messages.append(f"FAILURE: intersection between label and entry bounding boxes for `{ri.field['description']}` ({ri.rect}, {rj.rect})")
|
||||||
|
else:
|
||||||
|
messages.append(f"FAILURE: intersection between {ri.rect_type} bounding box for `{ri.field['description']}` ({ri.rect}) and {rj.rect_type} bounding box for `{rj.field['description']}` ({rj.rect})")
|
||||||
|
if len(messages) >= 20:
|
||||||
|
messages.append("Aborting further checks; fix bounding boxes and try again")
|
||||||
|
return messages
|
||||||
|
if ri.rect_type == "entry":
|
||||||
|
if "entry_text" in ri.field:
|
||||||
|
font_size = ri.field["entry_text"].get("font_size", 14)
|
||||||
|
entry_height = ri.rect[3] - ri.rect[1]
|
||||||
|
if entry_height < font_size:
|
||||||
|
has_error = True
|
||||||
|
messages.append(f"FAILURE: entry bounding box height ({entry_height}) for `{ri.field['description']}` is too short for the text content (font size: {font_size}). Increase the box height or decrease the font size.")
|
||||||
|
if len(messages) >= 20:
|
||||||
|
messages.append("Aborting further checks; fix bounding boxes and try again")
|
||||||
|
return messages
|
||||||
|
|
||||||
|
if not has_error:
|
||||||
|
messages.append("SUCCESS: All bounding boxes are valid")
|
||||||
|
return messages
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if len(sys.argv) != 2:
|
||||||
|
print("Usage: check_bounding_boxes.py [fields.json]")
|
||||||
|
sys.exit(1)
|
||||||
|
with open(sys.argv[1]) as f:
|
||||||
|
messages = get_bounding_box_messages(f)
|
||||||
|
for msg in messages:
|
||||||
|
print(msg)
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
import sys
|
||||||
|
from pypdf import PdfReader
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
reader = PdfReader(sys.argv[1])
|
||||||
|
if (reader.get_fields()):
|
||||||
|
print("This PDF has fillable form fields")
|
||||||
|
else:
|
||||||
|
print("This PDF does not have fillable form fields; you will need to visually determine where to enter data")
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from pdf2image import convert_from_path
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def convert(pdf_path, output_dir, max_dim=1000):
|
||||||
|
images = convert_from_path(pdf_path, dpi=200)
|
||||||
|
|
||||||
|
for i, image in enumerate(images):
|
||||||
|
width, height = image.size
|
||||||
|
if width > max_dim or height > max_dim:
|
||||||
|
scale_factor = min(max_dim / width, max_dim / height)
|
||||||
|
new_width = int(width * scale_factor)
|
||||||
|
new_height = int(height * scale_factor)
|
||||||
|
image = image.resize((new_width, new_height))
|
||||||
|
|
||||||
|
image_path = os.path.join(output_dir, f"page_{i+1}.png")
|
||||||
|
image.save(image_path)
|
||||||
|
print(f"Saved page {i+1} as {image_path} (size: {image.size})")
|
||||||
|
|
||||||
|
print(f"Converted {len(images)} pages to PNG images")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if len(sys.argv) != 3:
|
||||||
|
print("Usage: convert_pdf_to_images.py [input pdf] [output directory]")
|
||||||
|
sys.exit(1)
|
||||||
|
pdf_path = sys.argv[1]
|
||||||
|
output_directory = sys.argv[2]
|
||||||
|
convert(pdf_path, output_directory)
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
import json
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from PIL import Image, ImageDraw
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def create_validation_image(page_number, fields_json_path, input_path, output_path):
|
||||||
|
with open(fields_json_path, 'r') as f:
|
||||||
|
data = json.load(f)
|
||||||
|
|
||||||
|
img = Image.open(input_path)
|
||||||
|
draw = ImageDraw.Draw(img)
|
||||||
|
num_boxes = 0
|
||||||
|
|
||||||
|
for field in data["form_fields"]:
|
||||||
|
if field["page_number"] == page_number:
|
||||||
|
entry_box = field['entry_bounding_box']
|
||||||
|
label_box = field['label_bounding_box']
|
||||||
|
draw.rectangle(entry_box, outline='red', width=2)
|
||||||
|
draw.rectangle(label_box, outline='blue', width=2)
|
||||||
|
num_boxes += 2
|
||||||
|
|
||||||
|
img.save(output_path)
|
||||||
|
print(f"Created validation image at {output_path} with {num_boxes} bounding boxes")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if len(sys.argv) != 5:
|
||||||
|
print("Usage: create_validation_image.py [page number] [fields.json file] [input image path] [output image path]")
|
||||||
|
sys.exit(1)
|
||||||
|
page_number = int(sys.argv[1])
|
||||||
|
fields_json_path = sys.argv[2]
|
||||||
|
input_image_path = sys.argv[3]
|
||||||
|
output_image_path = sys.argv[4]
|
||||||
|
create_validation_image(page_number, fields_json_path, input_image_path, output_image_path)
|
||||||
@ -0,0 +1,122 @@
|
|||||||
|
import json
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from pypdf import PdfReader
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def get_full_annotation_field_id(annotation):
|
||||||
|
components = []
|
||||||
|
while annotation:
|
||||||
|
field_name = annotation.get('/T')
|
||||||
|
if field_name:
|
||||||
|
components.append(field_name)
|
||||||
|
annotation = annotation.get('/Parent')
|
||||||
|
return ".".join(reversed(components)) if components else None
|
||||||
|
|
||||||
|
|
||||||
|
def make_field_dict(field, field_id):
|
||||||
|
field_dict = {"field_id": field_id}
|
||||||
|
ft = field.get('/FT')
|
||||||
|
if ft == "/Tx":
|
||||||
|
field_dict["type"] = "text"
|
||||||
|
elif ft == "/Btn":
|
||||||
|
field_dict["type"] = "checkbox"
|
||||||
|
states = field.get("/_States_", [])
|
||||||
|
if len(states) == 2:
|
||||||
|
if "/Off" in states:
|
||||||
|
field_dict["checked_value"] = states[0] if states[0] != "/Off" else states[1]
|
||||||
|
field_dict["unchecked_value"] = "/Off"
|
||||||
|
else:
|
||||||
|
print(f"Unexpected state values for checkbox `${field_id}`. Its checked and unchecked values may not be correct; if you're trying to check it, visually verify the results.")
|
||||||
|
field_dict["checked_value"] = states[0]
|
||||||
|
field_dict["unchecked_value"] = states[1]
|
||||||
|
elif ft == "/Ch":
|
||||||
|
field_dict["type"] = "choice"
|
||||||
|
states = field.get("/_States_", [])
|
||||||
|
field_dict["choice_options"] = [{
|
||||||
|
"value": state[0],
|
||||||
|
"text": state[1],
|
||||||
|
} for state in states]
|
||||||
|
else:
|
||||||
|
field_dict["type"] = f"unknown ({ft})"
|
||||||
|
return field_dict
|
||||||
|
|
||||||
|
|
||||||
|
def get_field_info(reader: PdfReader):
|
||||||
|
fields = reader.get_fields()
|
||||||
|
|
||||||
|
field_info_by_id = {}
|
||||||
|
possible_radio_names = set()
|
||||||
|
|
||||||
|
for field_id, field in fields.items():
|
||||||
|
if field.get("/Kids"):
|
||||||
|
if field.get("/FT") == "/Btn":
|
||||||
|
possible_radio_names.add(field_id)
|
||||||
|
continue
|
||||||
|
field_info_by_id[field_id] = make_field_dict(field, field_id)
|
||||||
|
|
||||||
|
|
||||||
|
radio_fields_by_id = {}
|
||||||
|
|
||||||
|
for page_index, page in enumerate(reader.pages):
|
||||||
|
annotations = page.get('/Annots', [])
|
||||||
|
for ann in annotations:
|
||||||
|
field_id = get_full_annotation_field_id(ann)
|
||||||
|
if field_id in field_info_by_id:
|
||||||
|
field_info_by_id[field_id]["page"] = page_index + 1
|
||||||
|
field_info_by_id[field_id]["rect"] = ann.get('/Rect')
|
||||||
|
elif field_id in possible_radio_names:
|
||||||
|
try:
|
||||||
|
on_values = [v for v in ann["/AP"]["/N"] if v != "/Off"]
|
||||||
|
except KeyError:
|
||||||
|
continue
|
||||||
|
if len(on_values) == 1:
|
||||||
|
rect = ann.get("/Rect")
|
||||||
|
if field_id not in radio_fields_by_id:
|
||||||
|
radio_fields_by_id[field_id] = {
|
||||||
|
"field_id": field_id,
|
||||||
|
"type": "radio_group",
|
||||||
|
"page": page_index + 1,
|
||||||
|
"radio_options": [],
|
||||||
|
}
|
||||||
|
radio_fields_by_id[field_id]["radio_options"].append({
|
||||||
|
"value": on_values[0],
|
||||||
|
"rect": rect,
|
||||||
|
})
|
||||||
|
|
||||||
|
fields_with_location = []
|
||||||
|
for field_info in field_info_by_id.values():
|
||||||
|
if "page" in field_info:
|
||||||
|
fields_with_location.append(field_info)
|
||||||
|
else:
|
||||||
|
print(f"Unable to determine location for field id: {field_info.get('field_id')}, ignoring")
|
||||||
|
|
||||||
|
def sort_key(f):
|
||||||
|
if "radio_options" in f:
|
||||||
|
rect = f["radio_options"][0]["rect"] or [0, 0, 0, 0]
|
||||||
|
else:
|
||||||
|
rect = f.get("rect") or [0, 0, 0, 0]
|
||||||
|
adjusted_position = [-rect[1], rect[0]]
|
||||||
|
return [f.get("page"), adjusted_position]
|
||||||
|
|
||||||
|
sorted_fields = fields_with_location + list(radio_fields_by_id.values())
|
||||||
|
sorted_fields.sort(key=sort_key)
|
||||||
|
|
||||||
|
return sorted_fields
|
||||||
|
|
||||||
|
|
||||||
|
def write_field_info(pdf_path: str, json_output_path: str):
|
||||||
|
reader = PdfReader(pdf_path)
|
||||||
|
field_info = get_field_info(reader)
|
||||||
|
with open(json_output_path, "w") as f:
|
||||||
|
json.dump(field_info, f, indent=2)
|
||||||
|
print(f"Wrote {len(field_info)} fields to {json_output_path}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if len(sys.argv) != 3:
|
||||||
|
print("Usage: extract_form_field_info.py [input pdf] [output json]")
|
||||||
|
sys.exit(1)
|
||||||
|
write_field_info(sys.argv[1], sys.argv[2])
|
||||||
115
mateclaw-server/src/main/resources/skills/pdf/scripts/extract_form_structure.py
Executable file
115
mateclaw-server/src/main/resources/skills/pdf/scripts/extract_form_structure.py
Executable file
@ -0,0 +1,115 @@
|
|||||||
|
"""
|
||||||
|
Extract form structure from a non-fillable PDF.
|
||||||
|
|
||||||
|
This script analyzes the PDF to find:
|
||||||
|
- Text labels with their exact coordinates
|
||||||
|
- Horizontal lines (row boundaries)
|
||||||
|
- Checkboxes (small rectangles)
|
||||||
|
|
||||||
|
Output: A JSON file with the form structure that can be used to generate
|
||||||
|
accurate field coordinates for filling.
|
||||||
|
|
||||||
|
Usage: python extract_form_structure.py <input.pdf> <output.json>
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
import pdfplumber
|
||||||
|
|
||||||
|
|
||||||
|
def extract_form_structure(pdf_path):
|
||||||
|
structure = {
|
||||||
|
"pages": [],
|
||||||
|
"labels": [],
|
||||||
|
"lines": [],
|
||||||
|
"checkboxes": [],
|
||||||
|
"row_boundaries": []
|
||||||
|
}
|
||||||
|
|
||||||
|
with pdfplumber.open(pdf_path) as pdf:
|
||||||
|
for page_num, page in enumerate(pdf.pages, 1):
|
||||||
|
structure["pages"].append({
|
||||||
|
"page_number": page_num,
|
||||||
|
"width": float(page.width),
|
||||||
|
"height": float(page.height)
|
||||||
|
})
|
||||||
|
|
||||||
|
words = page.extract_words()
|
||||||
|
for word in words:
|
||||||
|
structure["labels"].append({
|
||||||
|
"page": page_num,
|
||||||
|
"text": word["text"],
|
||||||
|
"x0": round(float(word["x0"]), 1),
|
||||||
|
"top": round(float(word["top"]), 1),
|
||||||
|
"x1": round(float(word["x1"]), 1),
|
||||||
|
"bottom": round(float(word["bottom"]), 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
for line in page.lines:
|
||||||
|
if abs(float(line["x1"]) - float(line["x0"])) > page.width * 0.5:
|
||||||
|
structure["lines"].append({
|
||||||
|
"page": page_num,
|
||||||
|
"y": round(float(line["top"]), 1),
|
||||||
|
"x0": round(float(line["x0"]), 1),
|
||||||
|
"x1": round(float(line["x1"]), 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
for rect in page.rects:
|
||||||
|
width = float(rect["x1"]) - float(rect["x0"])
|
||||||
|
height = float(rect["bottom"]) - float(rect["top"])
|
||||||
|
if 5 <= width <= 15 and 5 <= height <= 15 and abs(width - height) < 2:
|
||||||
|
structure["checkboxes"].append({
|
||||||
|
"page": page_num,
|
||||||
|
"x0": round(float(rect["x0"]), 1),
|
||||||
|
"top": round(float(rect["top"]), 1),
|
||||||
|
"x1": round(float(rect["x1"]), 1),
|
||||||
|
"bottom": round(float(rect["bottom"]), 1),
|
||||||
|
"center_x": round((float(rect["x0"]) + float(rect["x1"])) / 2, 1),
|
||||||
|
"center_y": round((float(rect["top"]) + float(rect["bottom"])) / 2, 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
lines_by_page = {}
|
||||||
|
for line in structure["lines"]:
|
||||||
|
page = line["page"]
|
||||||
|
if page not in lines_by_page:
|
||||||
|
lines_by_page[page] = []
|
||||||
|
lines_by_page[page].append(line["y"])
|
||||||
|
|
||||||
|
for page, y_coords in lines_by_page.items():
|
||||||
|
y_coords = sorted(set(y_coords))
|
||||||
|
for i in range(len(y_coords) - 1):
|
||||||
|
structure["row_boundaries"].append({
|
||||||
|
"page": page,
|
||||||
|
"row_top": y_coords[i],
|
||||||
|
"row_bottom": y_coords[i + 1],
|
||||||
|
"row_height": round(y_coords[i + 1] - y_coords[i], 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
return structure
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if len(sys.argv) != 3:
|
||||||
|
print("Usage: extract_form_structure.py <input.pdf> <output.json>")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
pdf_path = sys.argv[1]
|
||||||
|
output_path = sys.argv[2]
|
||||||
|
|
||||||
|
print(f"Extracting structure from {pdf_path}...")
|
||||||
|
structure = extract_form_structure(pdf_path)
|
||||||
|
|
||||||
|
with open(output_path, "w") as f:
|
||||||
|
json.dump(structure, f, indent=2)
|
||||||
|
|
||||||
|
print(f"Found:")
|
||||||
|
print(f" - {len(structure['pages'])} pages")
|
||||||
|
print(f" - {len(structure['labels'])} text labels")
|
||||||
|
print(f" - {len(structure['lines'])} horizontal lines")
|
||||||
|
print(f" - {len(structure['checkboxes'])} checkboxes")
|
||||||
|
print(f" - {len(structure['row_boundaries'])} row boundaries")
|
||||||
|
print(f"Saved to {output_path}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@ -0,0 +1,98 @@
|
|||||||
|
import json
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from pypdf import PdfReader, PdfWriter
|
||||||
|
|
||||||
|
from extract_form_field_info import get_field_info
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def fill_pdf_fields(input_pdf_path: str, fields_json_path: str, output_pdf_path: str):
|
||||||
|
with open(fields_json_path) as f:
|
||||||
|
fields = json.load(f)
|
||||||
|
fields_by_page = {}
|
||||||
|
for field in fields:
|
||||||
|
if "value" in field:
|
||||||
|
field_id = field["field_id"]
|
||||||
|
page = field["page"]
|
||||||
|
if page not in fields_by_page:
|
||||||
|
fields_by_page[page] = {}
|
||||||
|
fields_by_page[page][field_id] = field["value"]
|
||||||
|
|
||||||
|
reader = PdfReader(input_pdf_path)
|
||||||
|
|
||||||
|
has_error = False
|
||||||
|
field_info = get_field_info(reader)
|
||||||
|
fields_by_ids = {f["field_id"]: f for f in field_info}
|
||||||
|
for field in fields:
|
||||||
|
existing_field = fields_by_ids.get(field["field_id"])
|
||||||
|
if not existing_field:
|
||||||
|
has_error = True
|
||||||
|
print(f"ERROR: `{field['field_id']}` is not a valid field ID")
|
||||||
|
elif field["page"] != existing_field["page"]:
|
||||||
|
has_error = True
|
||||||
|
print(f"ERROR: Incorrect page number for `{field['field_id']}` (got {field['page']}, expected {existing_field['page']})")
|
||||||
|
else:
|
||||||
|
if "value" in field:
|
||||||
|
err = validation_error_for_field_value(existing_field, field["value"])
|
||||||
|
if err:
|
||||||
|
print(err)
|
||||||
|
has_error = True
|
||||||
|
if has_error:
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
writer = PdfWriter(clone_from=reader)
|
||||||
|
for page, field_values in fields_by_page.items():
|
||||||
|
writer.update_page_form_field_values(writer.pages[page - 1], field_values, auto_regenerate=False)
|
||||||
|
|
||||||
|
writer.set_need_appearances_writer(True)
|
||||||
|
|
||||||
|
with open(output_pdf_path, "wb") as f:
|
||||||
|
writer.write(f)
|
||||||
|
|
||||||
|
|
||||||
|
def validation_error_for_field_value(field_info, field_value):
|
||||||
|
field_type = field_info["type"]
|
||||||
|
field_id = field_info["field_id"]
|
||||||
|
if field_type == "checkbox":
|
||||||
|
checked_val = field_info["checked_value"]
|
||||||
|
unchecked_val = field_info["unchecked_value"]
|
||||||
|
if field_value != checked_val and field_value != unchecked_val:
|
||||||
|
return f'ERROR: Invalid value "{field_value}" for checkbox field "{field_id}". The checked value is "{checked_val}" and the unchecked value is "{unchecked_val}"'
|
||||||
|
elif field_type == "radio_group":
|
||||||
|
option_values = [opt["value"] for opt in field_info["radio_options"]]
|
||||||
|
if field_value not in option_values:
|
||||||
|
return f'ERROR: Invalid value "{field_value}" for radio group field "{field_id}". Valid values are: {option_values}'
|
||||||
|
elif field_type == "choice":
|
||||||
|
choice_values = [opt["value"] for opt in field_info["choice_options"]]
|
||||||
|
if field_value not in choice_values:
|
||||||
|
return f'ERROR: Invalid value "{field_value}" for choice field "{field_id}". Valid values are: {choice_values}'
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def monkeypatch_pydpf_method():
|
||||||
|
from pypdf.generic import DictionaryObject
|
||||||
|
from pypdf.constants import FieldDictionaryAttributes
|
||||||
|
|
||||||
|
original_get_inherited = DictionaryObject.get_inherited
|
||||||
|
|
||||||
|
def patched_get_inherited(self, key: str, default = None):
|
||||||
|
result = original_get_inherited(self, key, default)
|
||||||
|
if key == FieldDictionaryAttributes.Opt:
|
||||||
|
if isinstance(result, list) and all(isinstance(v, list) and len(v) == 2 for v in result):
|
||||||
|
result = [r[0] for r in result]
|
||||||
|
return result
|
||||||
|
|
||||||
|
DictionaryObject.get_inherited = patched_get_inherited
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if len(sys.argv) != 4:
|
||||||
|
print("Usage: fill_fillable_fields.py [input pdf] [field_values.json] [output pdf]")
|
||||||
|
sys.exit(1)
|
||||||
|
monkeypatch_pydpf_method()
|
||||||
|
input_pdf = sys.argv[1]
|
||||||
|
fields_json = sys.argv[2]
|
||||||
|
output_pdf = sys.argv[3]
|
||||||
|
fill_pdf_fields(input_pdf, fields_json, output_pdf)
|
||||||
@ -0,0 +1,107 @@
|
|||||||
|
import json
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from pypdf import PdfReader, PdfWriter
|
||||||
|
from pypdf.annotations import FreeText
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def transform_from_image_coords(bbox, image_width, image_height, pdf_width, pdf_height):
|
||||||
|
x_scale = pdf_width / image_width
|
||||||
|
y_scale = pdf_height / image_height
|
||||||
|
|
||||||
|
left = bbox[0] * x_scale
|
||||||
|
right = bbox[2] * x_scale
|
||||||
|
|
||||||
|
top = pdf_height - (bbox[1] * y_scale)
|
||||||
|
bottom = pdf_height - (bbox[3] * y_scale)
|
||||||
|
|
||||||
|
return left, bottom, right, top
|
||||||
|
|
||||||
|
|
||||||
|
def transform_from_pdf_coords(bbox, pdf_height):
|
||||||
|
left = bbox[0]
|
||||||
|
right = bbox[2]
|
||||||
|
|
||||||
|
pypdf_top = pdf_height - bbox[1]
|
||||||
|
pypdf_bottom = pdf_height - bbox[3]
|
||||||
|
|
||||||
|
return left, pypdf_bottom, right, pypdf_top
|
||||||
|
|
||||||
|
|
||||||
|
def fill_pdf_form(input_pdf_path, fields_json_path, output_pdf_path):
|
||||||
|
|
||||||
|
with open(fields_json_path, "r") as f:
|
||||||
|
fields_data = json.load(f)
|
||||||
|
|
||||||
|
reader = PdfReader(input_pdf_path)
|
||||||
|
writer = PdfWriter()
|
||||||
|
|
||||||
|
writer.append(reader)
|
||||||
|
|
||||||
|
pdf_dimensions = {}
|
||||||
|
for i, page in enumerate(reader.pages):
|
||||||
|
mediabox = page.mediabox
|
||||||
|
pdf_dimensions[i + 1] = [mediabox.width, mediabox.height]
|
||||||
|
|
||||||
|
annotations = []
|
||||||
|
for field in fields_data["form_fields"]:
|
||||||
|
page_num = field["page_number"]
|
||||||
|
|
||||||
|
page_info = next(p for p in fields_data["pages"] if p["page_number"] == page_num)
|
||||||
|
pdf_width, pdf_height = pdf_dimensions[page_num]
|
||||||
|
|
||||||
|
if "pdf_width" in page_info:
|
||||||
|
transformed_entry_box = transform_from_pdf_coords(
|
||||||
|
field["entry_bounding_box"],
|
||||||
|
float(pdf_height)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
image_width = page_info["image_width"]
|
||||||
|
image_height = page_info["image_height"]
|
||||||
|
transformed_entry_box = transform_from_image_coords(
|
||||||
|
field["entry_bounding_box"],
|
||||||
|
image_width, image_height,
|
||||||
|
float(pdf_width), float(pdf_height)
|
||||||
|
)
|
||||||
|
|
||||||
|
if "entry_text" not in field or "text" not in field["entry_text"]:
|
||||||
|
continue
|
||||||
|
entry_text = field["entry_text"]
|
||||||
|
text = entry_text["text"]
|
||||||
|
if not text:
|
||||||
|
continue
|
||||||
|
|
||||||
|
font_name = entry_text.get("font", "Arial")
|
||||||
|
font_size = str(entry_text.get("font_size", 14)) + "pt"
|
||||||
|
font_color = entry_text.get("font_color", "000000")
|
||||||
|
|
||||||
|
annotation = FreeText(
|
||||||
|
text=text,
|
||||||
|
rect=transformed_entry_box,
|
||||||
|
font=font_name,
|
||||||
|
font_size=font_size,
|
||||||
|
font_color=font_color,
|
||||||
|
border_color=None,
|
||||||
|
background_color=None,
|
||||||
|
)
|
||||||
|
annotations.append(annotation)
|
||||||
|
writer.add_annotation(page_number=page_num - 1, annotation=annotation)
|
||||||
|
|
||||||
|
with open(output_pdf_path, "wb") as output:
|
||||||
|
writer.write(output)
|
||||||
|
|
||||||
|
print(f"Successfully filled PDF form and saved to {output_pdf_path}")
|
||||||
|
print(f"Added {len(annotations)} text annotations")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if len(sys.argv) != 4:
|
||||||
|
print("Usage: fill_pdf_form_with_annotations.py [input pdf] [fields.json] [output pdf]")
|
||||||
|
sys.exit(1)
|
||||||
|
input_pdf = sys.argv[1]
|
||||||
|
fields_json = sys.argv[2]
|
||||||
|
output_pdf = sys.argv[3]
|
||||||
|
|
||||||
|
fill_pdf_form(input_pdf, fields_json, output_pdf)
|
||||||
@ -0,0 +1,167 @@
|
|||||||
|
"""Named RGB palettes for pixel_art() and pixel_art_video().
|
||||||
|
|
||||||
|
Palette RGB values sourced from pixel-art-studio (MIT License)
|
||||||
|
https://github.com/Synero/pixel-art-studio — see ATTRIBUTION.md.
|
||||||
|
"""
|
||||||
|
|
||||||
|
PALETTES = {
|
||||||
|
# ── Hardware palettes ───────────────────────────────────────────────
|
||||||
|
"NES": [
|
||||||
|
(0, 0, 0), (124, 124, 124), (0, 0, 252), (0, 0, 188), (68, 40, 188),
|
||||||
|
(148, 0, 132), (168, 0, 32), (168, 16, 0), (136, 20, 0), (0, 116, 0),
|
||||||
|
(0, 148, 0), (0, 120, 0), (0, 88, 0), (0, 64, 88), (188, 188, 188),
|
||||||
|
(0, 120, 248), (0, 88, 248), (104, 68, 252), (216, 0, 204), (228, 0, 88),
|
||||||
|
(248, 56, 0), (228, 92, 16), (172, 124, 0), (0, 184, 0), (0, 168, 0),
|
||||||
|
(0, 168, 68), (0, 136, 136), (248, 248, 248), (60, 188, 252),
|
||||||
|
(104, 136, 252), (152, 120, 248), (248, 120, 248), (248, 88, 152),
|
||||||
|
(248, 120, 88), (252, 160, 68), (248, 184, 0), (184, 248, 24),
|
||||||
|
(88, 216, 84), (88, 248, 152), (0, 232, 216), (120, 120, 120),
|
||||||
|
(252, 252, 252), (164, 228, 252), (184, 184, 248), (216, 184, 248),
|
||||||
|
(248, 184, 248), (248, 164, 192), (240, 208, 176), (252, 224, 168),
|
||||||
|
(248, 216, 120), (216, 248, 120), (184, 248, 184), (184, 248, 216),
|
||||||
|
(0, 252, 252), (216, 216, 216),
|
||||||
|
],
|
||||||
|
"C64": [
|
||||||
|
(0, 0, 0), (255, 255, 255), (161, 77, 67), (106, 191, 199),
|
||||||
|
(161, 87, 164), (92, 172, 95), (64, 64, 223), (191, 206, 137),
|
||||||
|
(161, 104, 60), (108, 80, 21), (203, 126, 117), (98, 98, 98),
|
||||||
|
(137, 137, 137), (154, 226, 155), (124, 124, 255), (173, 173, 173),
|
||||||
|
],
|
||||||
|
"COMMODORE_64": [
|
||||||
|
(0, 0, 0), (255, 255, 255), (161, 77, 67), (106, 192, 200),
|
||||||
|
(161, 87, 165), (92, 172, 95), (64, 68, 227), (203, 214, 137),
|
||||||
|
(163, 104, 58), (110, 84, 11), (204, 127, 118), (99, 99, 99),
|
||||||
|
(139, 139, 139), (154, 227, 157), (139, 127, 205), (175, 175, 175),
|
||||||
|
],
|
||||||
|
"ZX_SPECTRUM": [
|
||||||
|
(0, 0, 0), (0, 39, 251), (252, 48, 22), (255, 63, 252),
|
||||||
|
(0, 249, 44), (0, 252, 254), (255, 253, 51), (255, 255, 255),
|
||||||
|
],
|
||||||
|
"APPLE_II_LO": [
|
||||||
|
(0, 0, 0), (133, 59, 81), (80, 71, 137), (234, 93, 240),
|
||||||
|
(0, 104, 82), (146, 146, 146), (0, 168, 241), (202, 195, 248),
|
||||||
|
(81, 92, 15), (235, 127, 35), (146, 146, 146), (246, 185, 202),
|
||||||
|
(0, 202, 41), (203, 211, 155), (155, 220, 203), (255, 255, 255),
|
||||||
|
],
|
||||||
|
"APPLE_II_HI": [
|
||||||
|
(0, 0, 0), (255, 0, 255), (0, 255, 0), (255, 255, 255),
|
||||||
|
(0, 175, 255), (255, 80, 0),
|
||||||
|
],
|
||||||
|
"GAMEBOY_ORIGINAL": [
|
||||||
|
(0, 63, 0), (46, 115, 32), (140, 191, 10), (160, 207, 10),
|
||||||
|
],
|
||||||
|
"GAMEBOY_POCKET": [
|
||||||
|
(0, 0, 0), (85, 85, 85), (170, 170, 170), (255, 255, 255),
|
||||||
|
],
|
||||||
|
"GAMEBOY_VIRTUALBOY": [
|
||||||
|
(239, 0, 0), (164, 0, 0), (85, 0, 0), (0, 0, 0),
|
||||||
|
],
|
||||||
|
"PICO_8": [
|
||||||
|
(0, 0, 0), (29, 43, 83), (126, 37, 83), (0, 135, 81), (171, 82, 54),
|
||||||
|
(95, 87, 79), (194, 195, 199), (255, 241, 232), (255, 0, 77),
|
||||||
|
(255, 163, 0), (255, 236, 39), (0, 228, 54), (41, 173, 255),
|
||||||
|
(131, 118, 156), (255, 119, 168), (255, 204, 170),
|
||||||
|
],
|
||||||
|
"TELETEXT": [
|
||||||
|
(0, 0, 0), (255, 0, 0), (0, 128, 0), (255, 255, 0),
|
||||||
|
(0, 0, 255), (255, 0, 255), (0, 255, 255), (255, 255, 255),
|
||||||
|
],
|
||||||
|
"CGA_MODE4_PAL1": [
|
||||||
|
(0, 0, 0), (255, 255, 255), (0, 255, 255), (255, 0, 255),
|
||||||
|
],
|
||||||
|
"MSX": [
|
||||||
|
(0, 0, 0), (62, 184, 73), (116, 208, 125), (89, 85, 224),
|
||||||
|
(128, 118, 241), (185, 94, 81), (101, 219, 239), (219, 101, 89),
|
||||||
|
(255, 137, 125), (204, 195, 94), (222, 208, 135), (58, 162, 65),
|
||||||
|
(183, 102, 181), (204, 204, 204), (255, 255, 255),
|
||||||
|
],
|
||||||
|
"MICROSOFT_WINDOWS_16": [
|
||||||
|
(0, 0, 0), (128, 0, 0), (0, 128, 0), (128, 128, 0), (0, 0, 128),
|
||||||
|
(128, 0, 128), (0, 128, 128), (192, 192, 192), (128, 128, 128),
|
||||||
|
(255, 0, 0), (0, 255, 0), (255, 255, 0), (0, 0, 255),
|
||||||
|
(255, 0, 255), (0, 255, 255), (255, 255, 255),
|
||||||
|
],
|
||||||
|
"MICROSOFT_WINDOWS_PAINT": [
|
||||||
|
(0, 0, 0), (255, 255, 255), (123, 123, 123), (189, 189, 189),
|
||||||
|
(123, 12, 2), (255, 37, 0), (123, 123, 2), (255, 251, 2),
|
||||||
|
(0, 123, 2), (2, 249, 2), (0, 123, 122), (2, 253, 254),
|
||||||
|
(2, 19, 122), (5, 50, 255), (123, 25, 122), (255, 64, 254),
|
||||||
|
(122, 57, 2), (255, 122, 57), (123, 123, 56), (255, 252, 122),
|
||||||
|
(2, 57, 57), (5, 250, 123), (0, 123, 255), (255, 44, 123),
|
||||||
|
],
|
||||||
|
"MONO_BW": [(0, 0, 0), (255, 255, 255)],
|
||||||
|
"MONO_AMBER": [(40, 40, 40), (255, 176, 0)],
|
||||||
|
"MONO_GREEN": [(40, 40, 40), (51, 255, 51)],
|
||||||
|
|
||||||
|
# ── Artistic palettes ───────────────────────────────────────────────
|
||||||
|
"PASTEL_DREAM": [
|
||||||
|
(255, 218, 233), (255, 229, 204), (255, 255, 204), (204, 255, 229),
|
||||||
|
(204, 229, 255), (229, 204, 255), (255, 204, 229), (204, 255, 255),
|
||||||
|
(255, 245, 220), (230, 230, 250),
|
||||||
|
],
|
||||||
|
"NEON_CYBER": [
|
||||||
|
(0, 0, 0), (255, 0, 128), (0, 255, 255), (255, 0, 255),
|
||||||
|
(0, 255, 128), (255, 255, 0), (128, 0, 255), (255, 128, 0),
|
||||||
|
(0, 128, 255), (255, 255, 255),
|
||||||
|
],
|
||||||
|
"RETRO_WARM": [
|
||||||
|
(62, 39, 35), (139, 69, 19), (210, 105, 30), (244, 164, 96),
|
||||||
|
(255, 218, 185), (255, 245, 238), (178, 34, 34), (205, 92, 92),
|
||||||
|
(255, 99, 71), (255, 160, 122),
|
||||||
|
],
|
||||||
|
"OCEAN_DEEP": [
|
||||||
|
(0, 25, 51), (0, 51, 102), (0, 76, 153), (0, 102, 178),
|
||||||
|
(0, 128, 204), (51, 153, 204), (102, 178, 204), (153, 204, 229),
|
||||||
|
(204, 229, 255), (229, 245, 255),
|
||||||
|
],
|
||||||
|
"FOREST_MOSS": [
|
||||||
|
(34, 51, 34), (51, 76, 51), (68, 102, 51), (85, 128, 68),
|
||||||
|
(102, 153, 85), (136, 170, 102), (170, 196, 136), (204, 221, 170),
|
||||||
|
(238, 238, 204), (245, 245, 220),
|
||||||
|
],
|
||||||
|
"SUNSET_FIRE": [
|
||||||
|
(51, 0, 0), (102, 0, 0), (153, 0, 0), (204, 0, 0), (255, 0, 0),
|
||||||
|
(255, 51, 0), (255, 102, 0), (255, 153, 0), (255, 204, 0),
|
||||||
|
(255, 255, 51),
|
||||||
|
],
|
||||||
|
"ARCTIC_ICE": [
|
||||||
|
(0, 0, 51), (0, 0, 102), (0, 51, 153), (0, 102, 153),
|
||||||
|
(51, 153, 204), (102, 204, 255), (153, 229, 255), (204, 242, 255),
|
||||||
|
(229, 247, 255), (255, 255, 255),
|
||||||
|
],
|
||||||
|
"VINTAGE_ROSE": [
|
||||||
|
(103, 58, 63), (137, 72, 81), (170, 91, 102), (196, 113, 122),
|
||||||
|
(219, 139, 147), (232, 168, 175), (240, 196, 199), (245, 215, 217),
|
||||||
|
(249, 232, 233), (255, 245, 245),
|
||||||
|
],
|
||||||
|
"EARTH_CLAY": [
|
||||||
|
(62, 39, 35), (89, 56, 47), (116, 73, 59), (143, 90, 71),
|
||||||
|
(170, 107, 83), (197, 124, 95), (210, 155, 126), (222, 186, 160),
|
||||||
|
(235, 217, 196), (248, 248, 232),
|
||||||
|
],
|
||||||
|
"ELECTRIC_VIOLET": [
|
||||||
|
(26, 0, 51), (51, 0, 102), (76, 0, 153), (102, 0, 204),
|
||||||
|
(128, 0, 255), (153, 51, 255), (178, 102, 255), (204, 153, 255),
|
||||||
|
(229, 204, 255), (245, 229, 255),
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def build_palette_image(palette_name):
|
||||||
|
"""Build a 1x1 PIL 'P'-mode image with the named palette for Image.quantize(palette=...)."""
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
if palette_name not in PALETTES:
|
||||||
|
raise ValueError(
|
||||||
|
f"Unknown palette {palette_name!r}. "
|
||||||
|
f"Choose from: {sorted(PALETTES)}"
|
||||||
|
)
|
||||||
|
flat = []
|
||||||
|
for (r, g, b) in PALETTES[palette_name]:
|
||||||
|
flat.extend([r, g, b])
|
||||||
|
# Pad to 768 bytes (256 colors) as PIL requires
|
||||||
|
while len(flat) < 768:
|
||||||
|
flat.append(0)
|
||||||
|
pal_img = Image.new("P", (1, 1))
|
||||||
|
pal_img.putpalette(flat)
|
||||||
|
return pal_img
|
||||||
@ -0,0 +1,162 @@
|
|||||||
|
"""Pixel art converter — Floyd-Steinberg dithering with preset or named palette.
|
||||||
|
|
||||||
|
Named hardware palettes (NES, GameBoy, PICO-8, C64, etc.) ported from
|
||||||
|
pixel-art-studio (MIT) — see ATTRIBUTION.md.
|
||||||
|
|
||||||
|
Usage (import):
|
||||||
|
from pixel_art import pixel_art
|
||||||
|
pixel_art("in.png", "out.png", preset="arcade")
|
||||||
|
pixel_art("in.png", "out.png", preset="nes")
|
||||||
|
pixel_art("in.png", "out.png", palette="PICO_8", block=6)
|
||||||
|
|
||||||
|
Usage (CLI):
|
||||||
|
python pixel_art.py in.png out.png --preset nes
|
||||||
|
"""
|
||||||
|
|
||||||
|
from PIL import Image, ImageEnhance, ImageOps
|
||||||
|
|
||||||
|
try:
|
||||||
|
from .palettes import PALETTES, build_palette_image
|
||||||
|
except ImportError:
|
||||||
|
from palettes import PALETTES, build_palette_image
|
||||||
|
|
||||||
|
|
||||||
|
PRESETS = {
|
||||||
|
# ── Original presets (adaptive palette) ─────────────────────────────
|
||||||
|
"arcade": {
|
||||||
|
"contrast": 1.8, "color": 1.5, "sharpness": 1.2,
|
||||||
|
"posterize_bits": 5, "block": 8, "palette": 16,
|
||||||
|
},
|
||||||
|
"snes": {
|
||||||
|
"contrast": 1.6, "color": 1.4, "sharpness": 1.2,
|
||||||
|
"posterize_bits": 6, "block": 4, "palette": 32,
|
||||||
|
},
|
||||||
|
# ── Hardware-accurate presets (named palette) ───────────────────────
|
||||||
|
"nes": {
|
||||||
|
"contrast": 1.5, "color": 1.4, "sharpness": 1.2,
|
||||||
|
"posterize_bits": 6, "block": 8, "palette": "NES",
|
||||||
|
},
|
||||||
|
"gameboy": {
|
||||||
|
"contrast": 1.5, "color": 1.0, "sharpness": 1.2,
|
||||||
|
"posterize_bits": 6, "block": 8, "palette": "GAMEBOY_ORIGINAL",
|
||||||
|
},
|
||||||
|
"gameboy_pocket": {
|
||||||
|
"contrast": 1.5, "color": 1.0, "sharpness": 1.2,
|
||||||
|
"posterize_bits": 6, "block": 8, "palette": "GAMEBOY_POCKET",
|
||||||
|
},
|
||||||
|
"pico8": {
|
||||||
|
"contrast": 1.6, "color": 1.3, "sharpness": 1.2,
|
||||||
|
"posterize_bits": 6, "block": 6, "palette": "PICO_8",
|
||||||
|
},
|
||||||
|
"c64": {
|
||||||
|
"contrast": 1.6, "color": 1.3, "sharpness": 1.2,
|
||||||
|
"posterize_bits": 6, "block": 8, "palette": "C64",
|
||||||
|
},
|
||||||
|
"apple2": {
|
||||||
|
"contrast": 1.8, "color": 1.4, "sharpness": 1.2,
|
||||||
|
"posterize_bits": 5, "block": 10, "palette": "APPLE_II_HI",
|
||||||
|
},
|
||||||
|
"teletext": {
|
||||||
|
"contrast": 1.8, "color": 1.5, "sharpness": 1.2,
|
||||||
|
"posterize_bits": 5, "block": 10, "palette": "TELETEXT",
|
||||||
|
},
|
||||||
|
"mspaint": {
|
||||||
|
"contrast": 1.6, "color": 1.4, "sharpness": 1.2,
|
||||||
|
"posterize_bits": 6, "block": 8, "palette": "MICROSOFT_WINDOWS_PAINT",
|
||||||
|
},
|
||||||
|
"mono_green": {
|
||||||
|
"contrast": 1.8, "color": 0.0, "sharpness": 1.2,
|
||||||
|
"posterize_bits": 5, "block": 6, "palette": "MONO_GREEN",
|
||||||
|
},
|
||||||
|
"mono_amber": {
|
||||||
|
"contrast": 1.8, "color": 0.0, "sharpness": 1.2,
|
||||||
|
"posterize_bits": 5, "block": 6, "palette": "MONO_AMBER",
|
||||||
|
},
|
||||||
|
# ── Artistic palette presets ────────────────────────────────────────
|
||||||
|
"neon": {
|
||||||
|
"contrast": 1.8, "color": 1.6, "sharpness": 1.2,
|
||||||
|
"posterize_bits": 5, "block": 6, "palette": "NEON_CYBER",
|
||||||
|
},
|
||||||
|
"pastel": {
|
||||||
|
"contrast": 1.2, "color": 1.3, "sharpness": 1.1,
|
||||||
|
"posterize_bits": 6, "block": 6, "palette": "PASTEL_DREAM",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def pixel_art(input_path, output_path, preset="arcade", **overrides):
|
||||||
|
"""Convert an image to retro pixel art.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
input_path: path to source image
|
||||||
|
output_path: path to save the resulting PNG
|
||||||
|
preset: one of PRESETS (arcade, snes, nes, gameboy, pico8, c64, ...)
|
||||||
|
**overrides: optionally override any preset field. In particular:
|
||||||
|
palette: int (adaptive N colors) OR str (named palette from PALETTES)
|
||||||
|
block: int pixel block size
|
||||||
|
contrast / color / sharpness / posterize_bits: numeric enhancers
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The resulting PIL.Image.
|
||||||
|
"""
|
||||||
|
if preset not in PRESETS:
|
||||||
|
raise ValueError(
|
||||||
|
f"Unknown preset {preset!r}. Choose from: {sorted(PRESETS)}"
|
||||||
|
)
|
||||||
|
cfg = {**PRESETS[preset], **overrides}
|
||||||
|
|
||||||
|
img = Image.open(input_path).convert("RGB")
|
||||||
|
|
||||||
|
img = ImageEnhance.Contrast(img).enhance(cfg["contrast"])
|
||||||
|
img = ImageEnhance.Color(img).enhance(cfg["color"])
|
||||||
|
img = ImageEnhance.Sharpness(img).enhance(cfg["sharpness"])
|
||||||
|
img = ImageOps.posterize(img, cfg["posterize_bits"])
|
||||||
|
|
||||||
|
w, h = img.size
|
||||||
|
block = cfg["block"]
|
||||||
|
small = img.resize(
|
||||||
|
(max(1, w // block), max(1, h // block)),
|
||||||
|
Image.NEAREST,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Quantize AFTER downscale so Floyd-Steinberg aligns with final pixel grid.
|
||||||
|
pal = cfg["palette"]
|
||||||
|
if isinstance(pal, str):
|
||||||
|
# Named hardware/artistic palette
|
||||||
|
pal_img = build_palette_image(pal)
|
||||||
|
quantized = small.quantize(palette=pal_img, dither=Image.FLOYDSTEINBERG)
|
||||||
|
else:
|
||||||
|
# Adaptive N-color palette (original behavior)
|
||||||
|
quantized = small.quantize(colors=int(pal), dither=Image.FLOYDSTEINBERG)
|
||||||
|
|
||||||
|
result = quantized.resize((w, h), Image.NEAREST)
|
||||||
|
result.save(output_path, "PNG")
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
import argparse
|
||||||
|
p = argparse.ArgumentParser(description="Convert image to pixel art.")
|
||||||
|
p.add_argument("input")
|
||||||
|
p.add_argument("output")
|
||||||
|
p.add_argument("--preset", default="arcade", choices=sorted(PRESETS))
|
||||||
|
p.add_argument("--palette", default=None,
|
||||||
|
help=f"Override palette: int or name from {sorted(PALETTES)}")
|
||||||
|
p.add_argument("--block", type=int, default=None)
|
||||||
|
args = p.parse_args()
|
||||||
|
|
||||||
|
overrides = {}
|
||||||
|
if args.palette is not None:
|
||||||
|
try:
|
||||||
|
overrides["palette"] = int(args.palette)
|
||||||
|
except ValueError:
|
||||||
|
overrides["palette"] = args.palette
|
||||||
|
if args.block is not None:
|
||||||
|
overrides["block"] = args.block
|
||||||
|
|
||||||
|
pixel_art(args.input, args.output, preset=args.preset, **overrides)
|
||||||
|
print(f"Wrote {args.output}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@ -0,0 +1,345 @@
|
|||||||
|
"""Pixel art video — overlay procedural animations onto a source image.
|
||||||
|
|
||||||
|
Takes any image (typically pre-processed with pixel_art()) and overlays
|
||||||
|
animated pixel effects (stars, rain, fireflies, etc.), then encodes to MP4
|
||||||
|
(and optionally GIF) via ffmpeg.
|
||||||
|
|
||||||
|
Scene animations ported from pixel-art-studio (MIT) — see ATTRIBUTION.md.
|
||||||
|
The generative/Pollinations code is intentionally dropped — the agent uses
|
||||||
|
`image_generate` + `pixel_art()` for base frames instead.
|
||||||
|
|
||||||
|
Usage (import):
|
||||||
|
from pixel_art_video import pixel_art_video
|
||||||
|
pixel_art_video("frame.png", "out.mp4", scene="night", duration=6)
|
||||||
|
|
||||||
|
Usage (CLI):
|
||||||
|
python pixel_art_video.py frame.png out.mp4 --scene night --duration 6 --gif
|
||||||
|
"""
|
||||||
|
|
||||||
|
import math
|
||||||
|
import os
|
||||||
|
import random
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
from PIL import Image, ImageDraw
|
||||||
|
|
||||||
|
|
||||||
|
# ── Pixel drawing helpers ──────────────────────────────────────────────
|
||||||
|
|
||||||
|
def _px(draw, x, y, color, size=2):
|
||||||
|
x, y = int(x), int(y)
|
||||||
|
W, H = draw.im.size
|
||||||
|
if 0 <= x < W and 0 <= y < H:
|
||||||
|
draw.rectangle([x, y, x + size - 1, y + size - 1], fill=color)
|
||||||
|
|
||||||
|
|
||||||
|
def _pixel_cross(draw, x, y, color, arm=2):
|
||||||
|
x, y = int(x), int(y)
|
||||||
|
for i in range(-arm, arm + 1):
|
||||||
|
_px(draw, x + i, y, color, 1)
|
||||||
|
_px(draw, x, y + i, color, 1)
|
||||||
|
|
||||||
|
|
||||||
|
# ── Animation init/draw pairs ──────────────────────────────────────────
|
||||||
|
|
||||||
|
def init_stars(rng, W, H):
|
||||||
|
return [(rng.randint(0, W), rng.randint(0, H // 2)) for _ in range(15)]
|
||||||
|
|
||||||
|
def draw_stars(draw, stars, t, W, H):
|
||||||
|
for i, (sx, sy) in enumerate(stars):
|
||||||
|
if math.sin(t * 2.0 + i * 0.7) > 0.65:
|
||||||
|
_pixel_cross(draw, sx, sy, (255, 255, 220), arm=2)
|
||||||
|
|
||||||
|
|
||||||
|
def init_fireflies(rng, W, H):
|
||||||
|
return [{"x": rng.randint(20, W - 20), "y": rng.randint(H // 4, H - 20),
|
||||||
|
"phase": rng.uniform(0, 6.28), "speed": rng.uniform(0.3, 0.8)}
|
||||||
|
for _ in range(10)]
|
||||||
|
|
||||||
|
def draw_fireflies(draw, ff, t, W, H):
|
||||||
|
for f in ff:
|
||||||
|
if math.sin(t * 1.5 + f["phase"]) < 0.15:
|
||||||
|
continue
|
||||||
|
_px(draw,
|
||||||
|
f["x"] + math.sin(t * f["speed"] + f["phase"]) * 3,
|
||||||
|
f["y"] + math.cos(t * f["speed"] * 0.7) * 2,
|
||||||
|
(200, 255, 100), 2)
|
||||||
|
|
||||||
|
|
||||||
|
def init_leaves(rng, W, H):
|
||||||
|
return [{"x": rng.randint(0, W), "y": rng.randint(-H, 0),
|
||||||
|
"speed": rng.uniform(0.5, 1.5), "wobble": rng.uniform(0.02, 0.05),
|
||||||
|
"phase": rng.uniform(0, 6.28),
|
||||||
|
"color": rng.choice([(180, 120, 50), (160, 100, 40), (200, 140, 60)])}
|
||||||
|
for _ in range(12)]
|
||||||
|
|
||||||
|
def draw_leaves(draw, leaves, t, W, H):
|
||||||
|
for leaf in leaves:
|
||||||
|
_px(draw,
|
||||||
|
leaf["x"] + math.sin(t * leaf["wobble"] + leaf["phase"]) * 15,
|
||||||
|
(leaf["y"] + t * leaf["speed"] * 20) % (H + 40) - 20,
|
||||||
|
leaf["color"], 2)
|
||||||
|
|
||||||
|
|
||||||
|
def init_dust_motes(rng, W, H):
|
||||||
|
return [{"x": rng.randint(30, W - 30), "y": rng.randint(30, H - 30),
|
||||||
|
"phase": rng.uniform(0, 6.28), "speed": rng.uniform(0.2, 0.5),
|
||||||
|
"amp": rng.uniform(2, 6)} for _ in range(20)]
|
||||||
|
|
||||||
|
def draw_dust_motes(draw, motes, t, W, H):
|
||||||
|
for m in motes:
|
||||||
|
if math.sin(t * 2.0 + m["phase"]) > 0.3:
|
||||||
|
_px(draw,
|
||||||
|
m["x"] + math.sin(t * 0.3 + m["phase"]) * m["amp"],
|
||||||
|
m["y"] - (m["speed"] * t * 15) % H,
|
||||||
|
(255, 210, 100), 1)
|
||||||
|
|
||||||
|
|
||||||
|
def init_sparkles(rng, W, H):
|
||||||
|
return [(rng.randint(W // 4, 3 * W // 4), rng.randint(H // 4, 3 * H // 4),
|
||||||
|
rng.uniform(0, 6.28),
|
||||||
|
rng.choice([(180, 200, 255), (255, 220, 150), (200, 180, 255)]))
|
||||||
|
for _ in range(10)]
|
||||||
|
|
||||||
|
def draw_sparkles(draw, sparkles, t, W, H):
|
||||||
|
for sx, sy, phase, color in sparkles:
|
||||||
|
if math.sin(t * 1.8 + phase) > 0.6:
|
||||||
|
_pixel_cross(draw, sx, sy, color, arm=2)
|
||||||
|
|
||||||
|
|
||||||
|
def init_rain(rng, W, H):
|
||||||
|
return [{"x": rng.randint(0, W), "y": rng.randint(0, H),
|
||||||
|
"speed": rng.uniform(4, 8)} for _ in range(30)]
|
||||||
|
|
||||||
|
def draw_rain(draw, rain, t, W, H):
|
||||||
|
for r in rain:
|
||||||
|
y = (r["y"] + t * r["speed"] * 20) % H
|
||||||
|
_px(draw, r["x"], y, (120, 150, 200), 1)
|
||||||
|
_px(draw, r["x"], y + 4, (100, 130, 180), 1)
|
||||||
|
|
||||||
|
|
||||||
|
def init_lightning(rng, W, H):
|
||||||
|
return {"timer": 0, "flash": False, "rng": rng}
|
||||||
|
|
||||||
|
def draw_lightning(draw, state, t, W, H):
|
||||||
|
state["timer"] += 1
|
||||||
|
if state["timer"] > 45 and state["rng"].random() < 0.04:
|
||||||
|
state["flash"] = True
|
||||||
|
state["timer"] = 0
|
||||||
|
if state["flash"]:
|
||||||
|
for x in range(0, W, 4):
|
||||||
|
for y in range(0, H // 3, 3):
|
||||||
|
if state["rng"].random() < 0.12:
|
||||||
|
_px(draw, x, y, (255, 255, 240), 2)
|
||||||
|
state["flash"] = False
|
||||||
|
|
||||||
|
|
||||||
|
def init_bubbles(rng, W, H):
|
||||||
|
return [{"x": rng.randint(20, W - 20), "y": rng.randint(H, H * 2),
|
||||||
|
"speed": rng.uniform(0.3, 0.8), "size": rng.choice([1, 2, 2])}
|
||||||
|
for _ in range(15)]
|
||||||
|
|
||||||
|
def draw_bubbles(draw, bubbles, t, W, H):
|
||||||
|
for b in bubbles:
|
||||||
|
x = b["x"] + math.sin(t * 0.5 + b["x"]) * 3
|
||||||
|
y = b["y"] - (t * b["speed"] * 20) % (H + 40)
|
||||||
|
if 0 < y < H:
|
||||||
|
_px(draw, x, y, (150, 200, 255), b["size"])
|
||||||
|
|
||||||
|
|
||||||
|
def init_embers(rng, W, H):
|
||||||
|
return [{"x": rng.randint(0, W), "y": rng.randint(0, H),
|
||||||
|
"speed": rng.uniform(0.3, 0.9), "phase": rng.uniform(0, 6.28),
|
||||||
|
"color": rng.choice([(255, 150, 30), (255, 100, 20), (255, 200, 50)])}
|
||||||
|
for _ in range(18)]
|
||||||
|
|
||||||
|
def draw_embers(draw, embers, t, W, H):
|
||||||
|
for e in embers:
|
||||||
|
x = e["x"] + math.sin(t * 0.4 + e["phase"]) * 5
|
||||||
|
y = e["y"] - (t * e["speed"] * 15) % H
|
||||||
|
if math.sin(t * 2.5 + e["phase"]) > 0.2:
|
||||||
|
_px(draw, x, y, e["color"], 2)
|
||||||
|
|
||||||
|
|
||||||
|
def init_snowflakes(rng, W, H):
|
||||||
|
return [{"x": rng.randint(0, W), "y": rng.randint(-H, 0),
|
||||||
|
"speed": rng.uniform(0.3, 0.6), "wobble": rng.uniform(0.04, 0.09),
|
||||||
|
"size": rng.choice([2, 2, 3])}
|
||||||
|
for _ in range(40)]
|
||||||
|
|
||||||
|
def draw_snowflakes(draw, flakes, t, W, H):
|
||||||
|
for f in flakes:
|
||||||
|
x = f["x"] + math.sin(t * f["wobble"] + f["x"]) * 20
|
||||||
|
y = (f["y"] + t * f["speed"] * 8) % (H + 20) - 10
|
||||||
|
if f["size"] >= 3:
|
||||||
|
_pixel_cross(draw, x, y, (230, 235, 255), arm=1)
|
||||||
|
else:
|
||||||
|
_px(draw, x, y, (230, 235, 255), 2)
|
||||||
|
|
||||||
|
|
||||||
|
def init_neon_pulse(rng, W, H):
|
||||||
|
return [(rng.randint(0, W), rng.randint(0, H), rng.uniform(0, 6.28),
|
||||||
|
rng.choice([(255, 0, 200), (0, 255, 255), (255, 50, 150)]))
|
||||||
|
for _ in range(8)]
|
||||||
|
|
||||||
|
def draw_neon_pulse(draw, points, t, W, H):
|
||||||
|
for x, y, phase, color in points:
|
||||||
|
if math.sin(t * 2.5 + phase) > 0.5:
|
||||||
|
_pixel_cross(draw, x, y, color, arm=3)
|
||||||
|
|
||||||
|
|
||||||
|
def init_heat_shimmer(rng, W, H):
|
||||||
|
return [{"x": rng.randint(0, W), "y": rng.randint(H // 2, H),
|
||||||
|
"phase": rng.uniform(0, 6.28)} for _ in range(12)]
|
||||||
|
|
||||||
|
def draw_heat_shimmer(draw, points, t, W, H):
|
||||||
|
for p in points:
|
||||||
|
x = p["x"] + math.sin(t * 0.8 + p["phase"]) * 2
|
||||||
|
y = p["y"] + math.sin(t * 1.2 + p["phase"]) * 1
|
||||||
|
if abs(math.sin(t * 1.5 + p["phase"])) > 0.6:
|
||||||
|
_px(draw, x, y, (255, 200, 100), 1)
|
||||||
|
|
||||||
|
|
||||||
|
# ── Scene → animation mapping ──────────────────────────────────────────
|
||||||
|
|
||||||
|
SCENES = {
|
||||||
|
"night": ["stars", "fireflies", "leaves"],
|
||||||
|
"dusk": ["fireflies", "sparkles"],
|
||||||
|
"tavern": ["dust_motes", "sparkles"],
|
||||||
|
"indoor": ["dust_motes"],
|
||||||
|
"urban": ["rain", "neon_pulse"],
|
||||||
|
"nature": ["leaves", "fireflies"],
|
||||||
|
"magic": ["sparkles", "fireflies"],
|
||||||
|
"storm": ["rain", "lightning"],
|
||||||
|
"underwater": ["bubbles", "sparkles"],
|
||||||
|
"fire": ["embers", "sparkles"],
|
||||||
|
"snow": ["snowflakes", "sparkles"],
|
||||||
|
"desert": ["heat_shimmer", "dust_motes"],
|
||||||
|
}
|
||||||
|
|
||||||
|
# Map scene layer name to (init_fn, draw_fn).
|
||||||
|
_LAYERS = {
|
||||||
|
"stars": (init_stars, draw_stars),
|
||||||
|
"fireflies": (init_fireflies, draw_fireflies),
|
||||||
|
"leaves": (init_leaves, draw_leaves),
|
||||||
|
"dust_motes": (init_dust_motes, draw_dust_motes),
|
||||||
|
"sparkles": (init_sparkles, draw_sparkles),
|
||||||
|
"rain": (init_rain, draw_rain),
|
||||||
|
"lightning": (init_lightning, draw_lightning),
|
||||||
|
"bubbles": (init_bubbles, draw_bubbles),
|
||||||
|
"embers": (init_embers, draw_embers),
|
||||||
|
"snowflakes": (init_snowflakes, draw_snowflakes),
|
||||||
|
"neon_pulse": (init_neon_pulse, draw_neon_pulse),
|
||||||
|
"heat_shimmer": (init_heat_shimmer, draw_heat_shimmer),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _ensure_ffmpeg():
|
||||||
|
if shutil.which("ffmpeg") is None:
|
||||||
|
raise RuntimeError(
|
||||||
|
"ffmpeg not found on PATH. Install via your package manager or "
|
||||||
|
"download from https://ffmpeg.org/"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def pixel_art_video(
|
||||||
|
base_image,
|
||||||
|
output_path,
|
||||||
|
scene="night",
|
||||||
|
duration=6,
|
||||||
|
fps=15,
|
||||||
|
seed=None,
|
||||||
|
export_gif=False,
|
||||||
|
):
|
||||||
|
"""Overlay pixel animations onto a base image and encode to MP4.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
base_image: path to source image (ideally already pixel-art styled)
|
||||||
|
output_path: path to MP4 output (GIF sibling written if export_gif=True)
|
||||||
|
scene: key from SCENES (night, urban, storm, snow, fire, ...)
|
||||||
|
duration: seconds of animation
|
||||||
|
fps: frames per second (default 15 for retro feel)
|
||||||
|
seed: optional int for reproducible animation placement
|
||||||
|
export_gif: also write a GIF alongside the MP4
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
(mp4_path, gif_path_or_None)
|
||||||
|
"""
|
||||||
|
if scene not in SCENES:
|
||||||
|
raise ValueError(
|
||||||
|
f"Unknown scene {scene!r}. Choose from: {sorted(SCENES)}"
|
||||||
|
)
|
||||||
|
_ensure_ffmpeg()
|
||||||
|
|
||||||
|
base = Image.open(base_image).convert("RGB")
|
||||||
|
W, H = base.size
|
||||||
|
|
||||||
|
rng = random.Random(seed if seed is not None else 42)
|
||||||
|
layers = []
|
||||||
|
for name in SCENES[scene]:
|
||||||
|
init_fn, draw_fn = _LAYERS[name]
|
||||||
|
layers.append((draw_fn, init_fn(rng, W, H)))
|
||||||
|
|
||||||
|
n_frames = fps * duration
|
||||||
|
os.makedirs(os.path.dirname(os.path.abspath(output_path)) or ".", exist_ok=True)
|
||||||
|
|
||||||
|
with tempfile.TemporaryDirectory(prefix="pixelart_frames_") as frames_dir:
|
||||||
|
for frame_idx in range(n_frames):
|
||||||
|
canvas = base.copy()
|
||||||
|
draw = ImageDraw.Draw(canvas)
|
||||||
|
t = frame_idx / fps
|
||||||
|
for draw_fn, state in layers:
|
||||||
|
draw_fn(draw, state, t, W, H)
|
||||||
|
canvas.save(os.path.join(frames_dir, f"frame_{frame_idx:04d}.png"))
|
||||||
|
|
||||||
|
subprocess.run(
|
||||||
|
["ffmpeg", "-y", "-loglevel", "error",
|
||||||
|
"-framerate", str(fps),
|
||||||
|
"-i", os.path.join(frames_dir, "frame_%04d.png"),
|
||||||
|
"-c:v", "libx264", "-pix_fmt", "yuv420p", "-crf", "18",
|
||||||
|
output_path],
|
||||||
|
check=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
gif_path = None
|
||||||
|
if export_gif:
|
||||||
|
gif_path = output_path.rsplit(".", 1)[0] + ".gif"
|
||||||
|
subprocess.run(
|
||||||
|
["ffmpeg", "-y", "-loglevel", "error",
|
||||||
|
"-framerate", str(fps),
|
||||||
|
"-i", os.path.join(frames_dir, "frame_%04d.png"),
|
||||||
|
"-vf",
|
||||||
|
"scale=320:-1:flags=neighbor,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse",
|
||||||
|
"-loop", "0",
|
||||||
|
gif_path],
|
||||||
|
check=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
return output_path, gif_path
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
import argparse
|
||||||
|
p = argparse.ArgumentParser(description="Overlay pixel animations onto an image → MP4.")
|
||||||
|
p.add_argument("base_image")
|
||||||
|
p.add_argument("output")
|
||||||
|
p.add_argument("--scene", default="night", choices=sorted(SCENES))
|
||||||
|
p.add_argument("--duration", type=int, default=6)
|
||||||
|
p.add_argument("--fps", type=int, default=15)
|
||||||
|
p.add_argument("--seed", type=int, default=None)
|
||||||
|
p.add_argument("--gif", action="store_true")
|
||||||
|
args = p.parse_args()
|
||||||
|
mp4, gif = pixel_art_video(
|
||||||
|
args.base_image, args.output,
|
||||||
|
scene=args.scene, duration=args.duration,
|
||||||
|
fps=args.fps, seed=args.seed, export_gif=args.gif,
|
||||||
|
)
|
||||||
|
print(f"Wrote {mp4}")
|
||||||
|
if gif:
|
||||||
|
print(f"Wrote {gif}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
195
mateclaw-server/src/main/resources/skills/pptx/scripts/add_slide.py
Executable file
195
mateclaw-server/src/main/resources/skills/pptx/scripts/add_slide.py
Executable file
@ -0,0 +1,195 @@
|
|||||||
|
"""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)
|
||||||
286
mateclaw-server/src/main/resources/skills/pptx/scripts/clean.py
Executable file
286
mateclaw-server/src/main/resources/skills/pptx/scripts/clean.py
Executable file
@ -0,0 +1,286 @@
|
|||||||
|
"""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")
|
||||||
@ -0,0 +1,199 @@
|
|||||||
|
"""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)
|
||||||
@ -0,0 +1,197 @@
|
|||||||
|
"""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."
|
||||||
|
)
|
||||||
159
mateclaw-server/src/main/resources/skills/pptx/scripts/office/pack.py
Executable file
159
mateclaw-server/src/main/resources/skills/pptx/scripts/office/pack.py
Executable file
@ -0,0 +1,159 @@
|
|||||||
|
"""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)
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,146 @@
|
|||||||
|
<?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>
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,11 @@
|
|||||||
|
<?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>
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,23 @@
|
|||||||
|
<?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>
|
||||||
@ -0,0 +1,185 @@
|
|||||||
|
<?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/spreadsheetDrawing"
|
||||||
|
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
||||||
|
targetNamespace="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"
|
||||||
|
elementFormDefault="qualified">
|
||||||
|
<xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/main"
|
||||||
|
schemaLocation="dml-main.xsd"/>
|
||||||
|
<xsd:import schemaLocation="shared-relationshipReference.xsd"
|
||||||
|
namespace="http://schemas.openxmlformats.org/officeDocument/2006/relationships"/>
|
||||||
|
<xsd:element name="from" type="CT_Marker"/>
|
||||||
|
<xsd:element name="to" type="CT_Marker"/>
|
||||||
|
<xsd:complexType name="CT_AnchorClientData">
|
||||||
|
<xsd:attribute name="fLocksWithSheet" type="xsd:boolean" use="optional" default="true"/>
|
||||||
|
<xsd:attribute name="fPrintsWithSheet" type="xsd:boolean" use="optional" default="true"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<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_GraphicalObjectFrameNonVisual">
|
||||||
|
<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_GraphicalObjectFrame">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="nvGraphicFramePr" type="CT_GraphicalObjectFrameNonVisual" 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_GraphicalObjectFrame"/>
|
||||||
|
<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_GraphicalObjectFrame"/>
|
||||||
|
<xsd:element name="cxnSp" type="CT_Connector"/>
|
||||||
|
<xsd:element name="pic" type="CT_Picture"/>
|
||||||
|
<xsd:element name="contentPart" type="CT_Rel"/>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:group>
|
||||||
|
<xsd:complexType name="CT_Rel">
|
||||||
|
<xsd:attribute ref="r:id" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_ColID">
|
||||||
|
<xsd:restriction base="xsd:int">
|
||||||
|
<xsd:minInclusive value="0"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_RowID">
|
||||||
|
<xsd:restriction base="xsd:int">
|
||||||
|
<xsd:minInclusive value="0"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_Marker">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="col" type="ST_ColID"/>
|
||||||
|
<xsd:element name="colOff" type="a:ST_Coordinate"/>
|
||||||
|
<xsd:element name="row" type="ST_RowID"/>
|
||||||
|
<xsd:element name="rowOff" type="a:ST_Coordinate"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_EditAs">
|
||||||
|
<xsd:restriction base="xsd:token">
|
||||||
|
<xsd:enumeration value="twoCell"/>
|
||||||
|
<xsd:enumeration value="oneCell"/>
|
||||||
|
<xsd:enumeration value="absolute"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_TwoCellAnchor">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="from" type="CT_Marker"/>
|
||||||
|
<xsd:element name="to" type="CT_Marker"/>
|
||||||
|
<xsd:group ref="EG_ObjectChoices"/>
|
||||||
|
<xsd:element name="clientData" type="CT_AnchorClientData" minOccurs="1" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="editAs" type="ST_EditAs" use="optional" default="twoCell"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_OneCellAnchor">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="from" type="CT_Marker"/>
|
||||||
|
<xsd:element name="ext" type="a:CT_PositiveSize2D"/>
|
||||||
|
<xsd:group ref="EG_ObjectChoices"/>
|
||||||
|
<xsd:element name="clientData" type="CT_AnchorClientData" minOccurs="1" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_AbsoluteAnchor">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="pos" type="a:CT_Point2D"/>
|
||||||
|
<xsd:element name="ext" type="a:CT_PositiveSize2D"/>
|
||||||
|
<xsd:group ref="EG_ObjectChoices"/>
|
||||||
|
<xsd:element name="clientData" type="CT_AnchorClientData" minOccurs="1" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:group name="EG_Anchor">
|
||||||
|
<xsd:choice>
|
||||||
|
<xsd:element name="twoCellAnchor" type="CT_TwoCellAnchor"/>
|
||||||
|
<xsd:element name="oneCellAnchor" type="CT_OneCellAnchor"/>
|
||||||
|
<xsd:element name="absoluteAnchor" type="CT_AbsoluteAnchor"/>
|
||||||
|
</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:element name="wsDr" type="CT_Drawing"/>
|
||||||
|
</xsd:schema>
|
||||||
@ -0,0 +1,287 @@
|
|||||||
|
<?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:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
|
||||||
|
xmlns:dpct="http://schemas.openxmlformats.org/drawingml/2006/picture"
|
||||||
|
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
||||||
|
xmlns="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"
|
||||||
|
targetNamespace="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"
|
||||||
|
elementFormDefault="qualified">
|
||||||
|
<xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/main"
|
||||||
|
schemaLocation="dml-main.xsd"/>
|
||||||
|
<xsd:import schemaLocation="wml.xsd"
|
||||||
|
namespace="http://schemas.openxmlformats.org/wordprocessingml/2006/main"/>
|
||||||
|
<xsd:import namespace="http://schemas.openxmlformats.org/drawingml/2006/picture"
|
||||||
|
schemaLocation="dml-picture.xsd"/>
|
||||||
|
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
|
||||||
|
schemaLocation="shared-relationshipReference.xsd"/>
|
||||||
|
<xsd:complexType name="CT_EffectExtent">
|
||||||
|
<xsd:attribute name="l" type="a:ST_Coordinate" use="required"/>
|
||||||
|
<xsd:attribute name="t" type="a:ST_Coordinate" use="required"/>
|
||||||
|
<xsd:attribute name="r" type="a:ST_Coordinate" use="required"/>
|
||||||
|
<xsd:attribute name="b" type="a:ST_Coordinate" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_WrapDistance">
|
||||||
|
<xsd:restriction base="xsd:unsignedInt"/>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_Inline">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="extent" type="a:CT_PositiveSize2D"/>
|
||||||
|
<xsd:element name="effectExtent" type="CT_EffectExtent" minOccurs="0"/>
|
||||||
|
<xsd:element name="docPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
|
||||||
|
<xsd:element name="cNvGraphicFramePr" type="a:CT_NonVisualGraphicFrameProperties"
|
||||||
|
minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xsd:element ref="a:graphic" minOccurs="1" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="distT" type="ST_WrapDistance" use="optional"/>
|
||||||
|
<xsd:attribute name="distB" type="ST_WrapDistance" use="optional"/>
|
||||||
|
<xsd:attribute name="distL" type="ST_WrapDistance" use="optional"/>
|
||||||
|
<xsd:attribute name="distR" type="ST_WrapDistance" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_WrapText">
|
||||||
|
<xsd:restriction base="xsd:token">
|
||||||
|
<xsd:enumeration value="bothSides"/>
|
||||||
|
<xsd:enumeration value="left"/>
|
||||||
|
<xsd:enumeration value="right"/>
|
||||||
|
<xsd:enumeration value="largest"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_WrapPath">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="start" type="a:CT_Point2D" minOccurs="1" maxOccurs="1"/>
|
||||||
|
<xsd:element name="lineTo" type="a:CT_Point2D" minOccurs="2" maxOccurs="unbounded"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="edited" type="xsd:boolean" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_WrapNone"/>
|
||||||
|
<xsd:complexType name="CT_WrapSquare">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="effectExtent" type="CT_EffectExtent" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="wrapText" type="ST_WrapText" use="required"/>
|
||||||
|
<xsd:attribute name="distT" type="ST_WrapDistance" use="optional"/>
|
||||||
|
<xsd:attribute name="distB" type="ST_WrapDistance" use="optional"/>
|
||||||
|
<xsd:attribute name="distL" type="ST_WrapDistance" use="optional"/>
|
||||||
|
<xsd:attribute name="distR" type="ST_WrapDistance" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_WrapTight">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="wrapPolygon" type="CT_WrapPath" minOccurs="1" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="wrapText" type="ST_WrapText" use="required"/>
|
||||||
|
<xsd:attribute name="distL" type="ST_WrapDistance" use="optional"/>
|
||||||
|
<xsd:attribute name="distR" type="ST_WrapDistance" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_WrapThrough">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="wrapPolygon" type="CT_WrapPath" minOccurs="1" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="wrapText" type="ST_WrapText" use="required"/>
|
||||||
|
<xsd:attribute name="distL" type="ST_WrapDistance" use="optional"/>
|
||||||
|
<xsd:attribute name="distR" type="ST_WrapDistance" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_WrapTopBottom">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="effectExtent" type="CT_EffectExtent" minOccurs="0"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="distT" type="ST_WrapDistance" use="optional"/>
|
||||||
|
<xsd:attribute name="distB" type="ST_WrapDistance" use="optional"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:group name="EG_WrapType">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:choice minOccurs="1" maxOccurs="1">
|
||||||
|
<xsd:element name="wrapNone" type="CT_WrapNone" minOccurs="1" maxOccurs="1"/>
|
||||||
|
<xsd:element name="wrapSquare" type="CT_WrapSquare" minOccurs="1" maxOccurs="1"/>
|
||||||
|
<xsd:element name="wrapTight" type="CT_WrapTight" minOccurs="1" maxOccurs="1"/>
|
||||||
|
<xsd:element name="wrapThrough" type="CT_WrapThrough" minOccurs="1" maxOccurs="1"/>
|
||||||
|
<xsd:element name="wrapTopAndBottom" type="CT_WrapTopBottom" minOccurs="1" maxOccurs="1"/>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:group>
|
||||||
|
<xsd:simpleType name="ST_PositionOffset">
|
||||||
|
<xsd:restriction base="xsd:int"/>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_AlignH">
|
||||||
|
<xsd:restriction base="xsd:token">
|
||||||
|
<xsd:enumeration value="left"/>
|
||||||
|
<xsd:enumeration value="right"/>
|
||||||
|
<xsd:enumeration value="center"/>
|
||||||
|
<xsd:enumeration value="inside"/>
|
||||||
|
<xsd:enumeration value="outside"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_RelFromH">
|
||||||
|
<xsd:restriction base="xsd:token">
|
||||||
|
<xsd:enumeration value="margin"/>
|
||||||
|
<xsd:enumeration value="page"/>
|
||||||
|
<xsd:enumeration value="column"/>
|
||||||
|
<xsd:enumeration value="character"/>
|
||||||
|
<xsd:enumeration value="leftMargin"/>
|
||||||
|
<xsd:enumeration value="rightMargin"/>
|
||||||
|
<xsd:enumeration value="insideMargin"/>
|
||||||
|
<xsd:enumeration value="outsideMargin"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_PosH">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:choice minOccurs="1" maxOccurs="1">
|
||||||
|
<xsd:element name="align" type="ST_AlignH" minOccurs="1" maxOccurs="1"/>
|
||||||
|
<xsd:element name="posOffset" type="ST_PositionOffset" minOccurs="1" maxOccurs="1"/>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="relativeFrom" type="ST_RelFromH" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:simpleType name="ST_AlignV">
|
||||||
|
<xsd:restriction base="xsd:token">
|
||||||
|
<xsd:enumeration value="top"/>
|
||||||
|
<xsd:enumeration value="bottom"/>
|
||||||
|
<xsd:enumeration value="center"/>
|
||||||
|
<xsd:enumeration value="inside"/>
|
||||||
|
<xsd:enumeration value="outside"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:simpleType name="ST_RelFromV">
|
||||||
|
<xsd:restriction base="xsd:token">
|
||||||
|
<xsd:enumeration value="margin"/>
|
||||||
|
<xsd:enumeration value="page"/>
|
||||||
|
<xsd:enumeration value="paragraph"/>
|
||||||
|
<xsd:enumeration value="line"/>
|
||||||
|
<xsd:enumeration value="topMargin"/>
|
||||||
|
<xsd:enumeration value="bottomMargin"/>
|
||||||
|
<xsd:enumeration value="insideMargin"/>
|
||||||
|
<xsd:enumeration value="outsideMargin"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_PosV">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:choice minOccurs="1" maxOccurs="1">
|
||||||
|
<xsd:element name="align" type="ST_AlignV" minOccurs="1" maxOccurs="1"/>
|
||||||
|
<xsd:element name="posOffset" type="ST_PositionOffset" minOccurs="1" maxOccurs="1"/>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="relativeFrom" type="ST_RelFromV" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_Anchor">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="simplePos" type="a:CT_Point2D"/>
|
||||||
|
<xsd:element name="positionH" type="CT_PosH"/>
|
||||||
|
<xsd:element name="positionV" type="CT_PosV"/>
|
||||||
|
<xsd:element name="extent" type="a:CT_PositiveSize2D"/>
|
||||||
|
<xsd:element name="effectExtent" type="CT_EffectExtent" minOccurs="0"/>
|
||||||
|
<xsd:group ref="EG_WrapType"/>
|
||||||
|
<xsd:element name="docPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
|
||||||
|
<xsd:element name="cNvGraphicFramePr" type="a:CT_NonVisualGraphicFrameProperties"
|
||||||
|
minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xsd:element ref="a:graphic" minOccurs="1" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="distT" type="ST_WrapDistance" use="optional"/>
|
||||||
|
<xsd:attribute name="distB" type="ST_WrapDistance" use="optional"/>
|
||||||
|
<xsd:attribute name="distL" type="ST_WrapDistance" use="optional"/>
|
||||||
|
<xsd:attribute name="distR" type="ST_WrapDistance" use="optional"/>
|
||||||
|
<xsd:attribute name="simplePos" type="xsd:boolean"/>
|
||||||
|
<xsd:attribute name="relativeHeight" type="xsd:unsignedInt" use="required"/>
|
||||||
|
<xsd:attribute name="behindDoc" type="xsd:boolean" use="required"/>
|
||||||
|
<xsd:attribute name="locked" type="xsd:boolean" use="required"/>
|
||||||
|
<xsd:attribute name="layoutInCell" type="xsd:boolean" use="required"/>
|
||||||
|
<xsd:attribute name="hidden" type="xsd:boolean" use="optional"/>
|
||||||
|
<xsd:attribute name="allowOverlap" type="xsd:boolean" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_TxbxContent">
|
||||||
|
<xsd:group ref="w:EG_BlockLevelElts" minOccurs="1" maxOccurs="unbounded"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_TextboxInfo">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="txbxContent" type="CT_TxbxContent" minOccurs="1" maxOccurs="1"/>
|
||||||
|
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="id" type="xsd:unsignedShort" use="optional" default="0"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_LinkedTextboxInformation">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="id" type="xsd:unsignedShort" use="required"/>
|
||||||
|
<xsd:attribute name="seq" type="xsd:unsignedShort" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_WordprocessingShape">
|
||||||
|
<xsd:sequence minOccurs="1" maxOccurs="1">
|
||||||
|
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xsd:choice minOccurs="1" maxOccurs="1">
|
||||||
|
<xsd:element name="cNvSpPr" type="a:CT_NonVisualDrawingShapeProps" minOccurs="1"
|
||||||
|
maxOccurs="1"/>
|
||||||
|
<xsd:element name="cNvCnPr" type="a:CT_NonVisualConnectorProperties" minOccurs="1"
|
||||||
|
maxOccurs="1"/>
|
||||||
|
</xsd:choice>
|
||||||
|
<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="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xsd:choice minOccurs="0" maxOccurs="1">
|
||||||
|
<xsd:element name="txbx" type="CT_TextboxInfo" minOccurs="1" maxOccurs="1"/>
|
||||||
|
<xsd:element name="linkedTxbx" type="CT_LinkedTextboxInformation" minOccurs="1"
|
||||||
|
maxOccurs="1"/>
|
||||||
|
</xsd:choice>
|
||||||
|
<xsd:element name="bodyPr" type="a:CT_TextBodyProperties" minOccurs="1" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="normalEastAsianFlow" type="xsd:boolean" use="optional" default="false"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_GraphicFrame">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="1" maxOccurs="1"/>
|
||||||
|
<xsd:element name="cNvFrPr" type="a:CT_NonVisualGraphicFrameProperties" 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:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_WordprocessingContentPartNonVisual">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xsd:element name="cNvContentPartPr" type="a:CT_NonVisualContentPartProperties" minOccurs="0" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_WordprocessingContentPart">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="nvContentPartPr" type="CT_WordprocessingContentPartNonVisual" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xsd:element name="xfrm" type="a:CT_Transform2D" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="bwMode" type="a:ST_BlackWhiteMode" use="optional"/>
|
||||||
|
<xsd:attribute ref="r:id" use="required"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_WordprocessingGroup">
|
||||||
|
<xsd:sequence minOccurs="1" maxOccurs="1">
|
||||||
|
<xsd:element name="cNvPr" type="a:CT_NonVisualDrawingProps" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xsd:element name="cNvGrpSpPr" type="a:CT_NonVisualGroupDrawingShapeProps" minOccurs="1"
|
||||||
|
maxOccurs="1"/>
|
||||||
|
<xsd:element name="grpSpPr" type="a:CT_GroupShapeProperties" minOccurs="1" maxOccurs="1"/>
|
||||||
|
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||||
|
<xsd:element ref="wsp"/>
|
||||||
|
<xsd:element name="grpSp" type="CT_WordprocessingGroup"/>
|
||||||
|
<xsd:element name="graphicFrame" type="CT_GraphicFrame"/>
|
||||||
|
<xsd:element ref="dpct:pic"/>
|
||||||
|
<xsd:element name="contentPart" type="CT_WordprocessingContentPart"/>
|
||||||
|
</xsd:choice>
|
||||||
|
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_WordprocessingCanvas">
|
||||||
|
<xsd:sequence minOccurs="1" maxOccurs="1">
|
||||||
|
<xsd:element name="bg" type="a:CT_BackgroundFormatting" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xsd:element name="whole" type="a:CT_WholeE2oFormatting" minOccurs="0" maxOccurs="1"/>
|
||||||
|
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||||
|
<xsd:element ref="wsp"/>
|
||||||
|
<xsd:element ref="dpct:pic"/>
|
||||||
|
<xsd:element name="contentPart" type="CT_WordprocessingContentPart"/>
|
||||||
|
<xsd:element ref="wgp"/>
|
||||||
|
<xsd:element name="graphicFrame" type="CT_GraphicFrame"/>
|
||||||
|
</xsd:choice>
|
||||||
|
<xsd:element name="extLst" type="a:CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:element name="wpc" type="CT_WordprocessingCanvas"/>
|
||||||
|
<xsd:element name="wgp" type="CT_WordprocessingGroup"/>
|
||||||
|
<xsd:element name="wsp" type="CT_WordprocessingShape"/>
|
||||||
|
<xsd:element name="inline" type="CT_Inline"/>
|
||||||
|
<xsd:element name="anchor" type="CT_Anchor"/>
|
||||||
|
</xsd:schema>
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,28 @@
|
|||||||
|
<?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>
|
||||||
@ -0,0 +1,144 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||||
|
xmlns="http://schemas.openxmlformats.org/officeDocument/2006/bibliography"
|
||||||
|
xmlns:s="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||||
|
targetNamespace="http://schemas.openxmlformats.org/officeDocument/2006/bibliography"
|
||||||
|
elementFormDefault="qualified">
|
||||||
|
<xsd:import namespace="http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes"
|
||||||
|
schemaLocation="shared-commonSimpleTypes.xsd"/>
|
||||||
|
<xsd:simpleType name="ST_SourceType">
|
||||||
|
<xsd:restriction base="s:ST_String">
|
||||||
|
<xsd:enumeration value="ArticleInAPeriodical"/>
|
||||||
|
<xsd:enumeration value="Book"/>
|
||||||
|
<xsd:enumeration value="BookSection"/>
|
||||||
|
<xsd:enumeration value="JournalArticle"/>
|
||||||
|
<xsd:enumeration value="ConferenceProceedings"/>
|
||||||
|
<xsd:enumeration value="Report"/>
|
||||||
|
<xsd:enumeration value="SoundRecording"/>
|
||||||
|
<xsd:enumeration value="Performance"/>
|
||||||
|
<xsd:enumeration value="Art"/>
|
||||||
|
<xsd:enumeration value="DocumentFromInternetSite"/>
|
||||||
|
<xsd:enumeration value="InternetSite"/>
|
||||||
|
<xsd:enumeration value="Film"/>
|
||||||
|
<xsd:enumeration value="Interview"/>
|
||||||
|
<xsd:enumeration value="Patent"/>
|
||||||
|
<xsd:enumeration value="ElectronicSource"/>
|
||||||
|
<xsd:enumeration value="Case"/>
|
||||||
|
<xsd:enumeration value="Misc"/>
|
||||||
|
</xsd:restriction>
|
||||||
|
</xsd:simpleType>
|
||||||
|
<xsd:complexType name="CT_NameListType">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="Person" type="CT_PersonType" minOccurs="1" maxOccurs="unbounded"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_PersonType">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="Last" type="s:ST_String" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
<xsd:element name="First" type="s:ST_String" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
<xsd:element name="Middle" type="s:ST_String" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_NameType">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="NameList" type="CT_NameListType" minOccurs="1" maxOccurs="1"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_NameOrCorporateType">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:choice minOccurs="0" maxOccurs="1">
|
||||||
|
<xsd:element name="NameList" type="CT_NameListType" minOccurs="1" maxOccurs="1"/>
|
||||||
|
<xsd:element name="Corporate" minOccurs="1" maxOccurs="1" type="s:ST_String"/>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_AuthorType">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||||
|
<xsd:element name="Artist" type="CT_NameType"/>
|
||||||
|
<xsd:element name="Author" type="CT_NameOrCorporateType"/>
|
||||||
|
<xsd:element name="BookAuthor" type="CT_NameType"/>
|
||||||
|
<xsd:element name="Compiler" type="CT_NameType"/>
|
||||||
|
<xsd:element name="Composer" type="CT_NameType"/>
|
||||||
|
<xsd:element name="Conductor" type="CT_NameType"/>
|
||||||
|
<xsd:element name="Counsel" type="CT_NameType"/>
|
||||||
|
<xsd:element name="Director" type="CT_NameType"/>
|
||||||
|
<xsd:element name="Editor" type="CT_NameType"/>
|
||||||
|
<xsd:element name="Interviewee" type="CT_NameType"/>
|
||||||
|
<xsd:element name="Interviewer" type="CT_NameType"/>
|
||||||
|
<xsd:element name="Inventor" type="CT_NameType"/>
|
||||||
|
<xsd:element name="Performer" type="CT_NameOrCorporateType"/>
|
||||||
|
<xsd:element name="ProducerName" type="CT_NameType"/>
|
||||||
|
<xsd:element name="Translator" type="CT_NameType"/>
|
||||||
|
<xsd:element name="Writer" type="CT_NameType"/>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:complexType name="CT_SourceType">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||||
|
<xsd:element name="AbbreviatedCaseNumber" type="s:ST_String"/>
|
||||||
|
<xsd:element name="AlbumTitle" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Author" type="CT_AuthorType"/>
|
||||||
|
<xsd:element name="BookTitle" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Broadcaster" type="s:ST_String"/>
|
||||||
|
<xsd:element name="BroadcastTitle" type="s:ST_String"/>
|
||||||
|
<xsd:element name="CaseNumber" type="s:ST_String"/>
|
||||||
|
<xsd:element name="ChapterNumber" type="s:ST_String"/>
|
||||||
|
<xsd:element name="City" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Comments" type="s:ST_String"/>
|
||||||
|
<xsd:element name="ConferenceName" type="s:ST_String"/>
|
||||||
|
<xsd:element name="CountryRegion" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Court" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Day" type="s:ST_String"/>
|
||||||
|
<xsd:element name="DayAccessed" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Department" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Distributor" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Edition" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Guid" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Institution" type="s:ST_String"/>
|
||||||
|
<xsd:element name="InternetSiteTitle" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Issue" type="s:ST_String"/>
|
||||||
|
<xsd:element name="JournalName" type="s:ST_String"/>
|
||||||
|
<xsd:element name="LCID" type="s:ST_Lang"/>
|
||||||
|
<xsd:element name="Medium" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Month" type="s:ST_String"/>
|
||||||
|
<xsd:element name="MonthAccessed" type="s:ST_String"/>
|
||||||
|
<xsd:element name="NumberVolumes" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Pages" type="s:ST_String"/>
|
||||||
|
<xsd:element name="PatentNumber" type="s:ST_String"/>
|
||||||
|
<xsd:element name="PeriodicalTitle" type="s:ST_String"/>
|
||||||
|
<xsd:element name="ProductionCompany" type="s:ST_String"/>
|
||||||
|
<xsd:element name="PublicationTitle" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Publisher" type="s:ST_String"/>
|
||||||
|
<xsd:element name="RecordingNumber" type="s:ST_String"/>
|
||||||
|
<xsd:element name="RefOrder" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Reporter" type="s:ST_String"/>
|
||||||
|
<xsd:element name="SourceType" type="ST_SourceType"/>
|
||||||
|
<xsd:element name="ShortTitle" type="s:ST_String"/>
|
||||||
|
<xsd:element name="StandardNumber" type="s:ST_String"/>
|
||||||
|
<xsd:element name="StateProvince" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Station" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Tag" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Theater" type="s:ST_String"/>
|
||||||
|
<xsd:element name="ThesisType" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Title" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Type" type="s:ST_String"/>
|
||||||
|
<xsd:element name="URL" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Version" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Volume" type="s:ST_String"/>
|
||||||
|
<xsd:element name="Year" type="s:ST_String"/>
|
||||||
|
<xsd:element name="YearAccessed" type="s:ST_String"/>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
<xsd:element name="Sources" type="CT_Sources"/>
|
||||||
|
<xsd:complexType name="CT_Sources">
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="Source" type="CT_SourceType" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="SelectedStyle" type="s:ST_String"/>
|
||||||
|
<xsd:attribute name="StyleName" type="s:ST_String"/>
|
||||||
|
<xsd:attribute name="URI" type="s:ST_String"/>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:schema>
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user