Task 847: .XSN File Format
Task 847: .XSN File Format
1. Properties of the .XSN File Format Intrinsic to Its File System
The .XSN file format is a Microsoft Cabinet (.CAB) archive with a .xsn extension, used for Microsoft InfoPath form templates. Its structure is defined by the InfoPath Form Template Format specification, where the archive contains XML-based files that define the form's data structure, appearance, behavior, and resources. The key intrinsic properties are derived from the required form definition file (manifest.xsf), which is an XML document outlining the form's configuration. These properties include attributes and sections that govern the form's metadata, components, and functionality. Below is a comprehensive list based on the format's specification:
- Form Name: The identifier for the form template (e.g., from the
nameattribute inxDocumentClass). - Solution Version: The version of the form template (e.g.,
solutionVersionattribute). - Product Version: The required InfoPath version for compatibility (e.g.,
productVersionattribute). - Publish URL: The location where the form is published (e.g.,
publishUrlattribute). - Trust Level: Security level, such as "domain" or "fullTrust" (e.g.,
trustLevelattribute). - Require Full Trust: Indicator for whether the form needs elevated permissions (e.g.,
requireFullTrustattribute). - Package Files: A list of all files in the archive (under
packageandfileselements), including: - Required files:
manifest.xsf,template.xml(default form data),sampledata.xml(sample instance data), view-specific.xslfiles (e.g.,view1.xslfor rendering views), schema.xsdfiles (e.g.,myschema.xsdfor data validation). - Optional files:
upgrade.xsl(for version upgrades), script files (e.g.,script.jsfor custom code), resource files (e.g., images or additional XML). - File Properties (for each file in the package):
- Namespace: The XML namespace (e.g., for schema files).
- Editability: Level of edit permissions (e.g., "full" or "none").
- Root Element: The root XML element for schemas (e.g., "myFields").
- Use On-Demand Algorithm: Indicator for optimized loading (e.g., "yes").
- List Properties: Definitions for integration with lists (under
listProperties): - Fields: A collection of field definitions, each with:
- Name: Field identifier.
- Column Name: Corresponding list column.
- Node: XPath to the data node.
- Type: Data type (e.g., "xsd:string", "xsd:date").
- Views: List of form views, including default view and associated
.xslfiles. - Data Connections: Configurations for external data sources (e.g., web services, databases).
- Rules: Business logic rules for validation and actions.
- Calculations: Formulas for computed fields.
- Script Elements: References to custom scripts, if present (may affect browser compatibility).
These properties are intrinsic as they define the file's internal organization, validation, and runtime behavior within the InfoPath ecosystem.
2. Direct Download Links for .XSN Files
Two direct download links to sample .XSN files are provided below:
- http://www.infopathdev.com/blogs/hilary/FilteredTarget/FilterTargetField.xsn (Sample form demonstrating filtered rules).
- https://www.infopathdev.com/files/folders/99433/download.aspx (Expense Reports Dashboard starter template).
3. Ghost Blog Embedded HTML JavaScript for Drag-and-Drop .XSN File Dump
The following is embeddable HTML with JavaScript for a blog post. It allows users to drag and drop a .XSN file, extracts the manifest.xsf (assuming a basic CAB decompression implementation, as JavaScript lacks native CAB support; a third-party library like JSZip with CAB extension or custom parser would be needed in production). It then parses the XML and dumps the properties to the screen. For simplicity, the code includes a placeholder for CAB extraction; in practice, integrate a library such as pako for compression handling.
4. Python Class for .XSN File Handling
The following Python class uses the cabarchive library (note: install via pip if needed, as it is not standard; alternatively, use struct for manual parsing). It opens a .XSN file, extracts the manifest.xsf, parses it with xml.etree.ElementTree, and provides methods to read, write (update properties), and print properties.
import os
import xml.etree.ElementTree as ET
from io import BytesIO
# Assume cabarchive library for CAB handling (pip install cabarchive if available)
from cabarchive import CabArchive
class XSNHandler:
def __init__(self, filepath):
self.filepath = filepath
self.manifest = None
self.extracted_files = None
self._load()
def _load(self):
with open(self.filepath, 'rb') as f:
cab_data = f.read()
self.extracted_files = CabArchive(BytesIO(cab_data))
manifest_data = self.extracted_files['manifest.xsf'].buf
self.manifest = ET.fromstring(manifest_data)
def read_properties(self):
properties = {}
xdoc = self.manifest
properties['form_name'] = xdoc.get('name')
properties['solution_version'] = xdoc.get('solutionVersion')
properties['product_version'] = xdoc.get('productVersion')
properties['publish_url'] = xdoc.get('publishUrl')
properties['trust_level'] = xdoc.get('trustLevel')
properties['require_full_trust'] = xdoc.get('requireFullTrust')
properties['package_files'] = []
for file_elem in xdoc.findall('.//files/file'):
file_info = {'name': file_elem.get('name')}
props_elem = file_elem.find('fileProperties')
if props_elem is not None:
file_info['namespace'] = props_elem.get('namespace')
file_info['editability'] = props_elem.get('editability')
file_info['root_element'] = props_elem.get('rootElement')
file_info['use_on_demand'] = props_elem.get('useOnDemandAlgorithm')
properties['package_files'].append(file_info)
properties['list_fields'] = []
for field_elem in xdoc.findall('.//listProperties/fields/field'):
properties['list_fields'].append({
'name': field_elem.get('name'),
'column_name': field_elem.get('columnName'),
'node': field_elem.get('node'),
'type': field_elem.get('type')
})
properties['views_count'] = len(xdoc.findall('.//views/view'))
properties['data_connections_count'] = len(xdoc.findall('.//dataConnections/dataConnection'))
properties['rules_count'] = len(xdoc.findall('.//rules/rule'))
properties['calculations_count'] = len(xdoc.findall('.//calculations/calculation'))
properties['script_present'] = 'script' in [elem.tag for elem in xdoc]
return properties
def print_properties(self):
props = self.read_properties()
print("Properties:")
for key, value in props.items():
if isinstance(value, list):
print(f"{key.capitalize()}:")
for item in value:
print(f" {item}")
else:
print(f"- {key.replace('_', ' ').capitalize()}: {value}")
def write_properties(self, updates):
# Update example: updates = {'form_name': 'NewName'}
for key, value in updates.items():
if key == 'form_name':
self.manifest.set('name', value)
# Add similar for other properties...
# Rebuild CAB (simplified; update manifest and repack)
self.extracted_files['manifest.xsf'].buf = ET.tostring(self.manifest)
with open(self.filepath, 'wb') as f:
f.write(self.extracted_files.save())
# Usage example:
# handler = XSNHandler('example.xsn')
# handler.print_properties()
# handler.write_properties({'form_name': 'Updated Form'})
5. Java Class for .XSN File Handling
The following Java class uses Apache Commons Compress for CAB handling (assume dependency added). It opens the .XSN, extracts and parses manifest.xsf with DOM, and supports read, write, and print operations.
import org.apache.commons.compress.archivers.cab.CabArchiveEntry;
import org.apache.commons.compress.archivers.cab.CabArchiveInputStream;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
public class XSNHandler {
private String filepath;
private Document manifest;
public XSNHandler(String filepath) throws Exception {
this.filepath = filepath;
load();
}
private void load() throws Exception {
try (FileInputStream fis = new FileInputStream(filepath);
CabArchiveInputStream cabIn = new CabArchiveInputStream(fis)) {
CabArchiveEntry entry;
while ((entry = cabIn.getNextEntry()) != null) {
if (entry.getName().equals("manifest.xsf")) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = cabIn.read(buffer)) > 0) {
baos.write(buffer, 0, len);
}
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
manifest = db.parse(new ByteArrayInputStream(baos.toByteArray()));
return;
}
}
}
throw new Exception("manifest.xsf not found");
}
public Map<String, Object> readProperties() {
Map<String, Object> properties = new HashMap<>();
Element xdoc = manifest.getDocumentElement();
properties.put("form_name", xdoc.getAttribute("name"));
properties.put("solution_version", xdoc.getAttribute("solutionVersion"));
properties.put("product_version", xdoc.getAttribute("productVersion"));
properties.put("publish_url", xdoc.getAttribute("publishUrl"));
properties.put("trust_level", xdoc.getAttribute("trustLevel"));
properties.put("require_full_trust", xdoc.getAttribute("requireFullTrust"));
// Package files and other properties similarly as in Python...
return properties;
}
public void printProperties() {
Map<String, Object> props = readProperties();
System.out.println("Properties:");
props.forEach((key, value) -> System.out.println("- " + key.replace("_", " ").substring(0, 1).toUpperCase() + key.replace("_", " ").substring(1) + ": " + value));
}
public void writeProperties(Map<String, String> updates) throws Exception {
// Update document...
// Then repack CAB (implement repacking logic using CabArchiveOutputStream)
}
// Main for testing
public static void main(String[] args) throws Exception {
XSNHandler handler = new XSNHandler("example.xsn");
handler.printProperties();
}
}
Note: Full write implementation requires CAB repacking, omitted for brevity; extend with Apache Commons Compress output stream.
6. JavaScript Class for .XSN File Handling
The following JavaScript class (Node.js compatible) uses a CAB parser (assume 'cabextract-js' or custom; for browser, adapt from section 3). It reads the file, extracts manifest.xsf, parses with DOMParser, and supports read, write, print.
const fs = require('fs');
const { DOMParser, XMLSerializer } = require('xmldom'); // npm install xmldom
class XSNHandler {
constructor(filepath) {
this.filepath = filepath;
this.manifest = null;
this.load();
}
load() {
const data = fs.readFileSync(this.filepath);
// Placeholder CAB extraction: Implement or use library to get manifest content as string.
const manifestContent = extractCab(data, 'manifest.xsf'); // Custom function
const parser = new DOMParser();
this.manifest = parser.parseFromString(manifestContent, 'application/xml');
}
readProperties() {
const properties = {};
const xdoc = this.manifest.documentElement;
properties.formName = xdoc.getAttribute('name');
// Similar to HTML JS extraction...
return properties;
}
printProperties() {
const props = this.readProperties();
console.log('Properties:');
Object.entries(props).forEach(([key, value]) => console.log(`- ${key}: ${value}`));
}
writeProperties(updates) {
// Update attributes...
// Serialize and repack CAB
const serializer = new XMLSerializer();
const updatedManifest = serializer.serializeToString(this.manifest);
// Repack logic...
}
}
// Placeholder
function extractCab(data, fileName) {
// Implement CAB extraction
return ''; // Return file content string
}
// Usage:
// const handler = new XSNHandler('example.xsn');
// handler.printProperties();
7. C "Class" (Struct with Functions) for .XSN File Handling
C lacks classes, so the following uses a struct with associated functions. For CAB handling, assume a library like libmspack (include via headers; compile with it). It opens, extracts, parses XML (using a simple XML parser like minixml or custom), and supports operations.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Assume mspack.h for CAB (libmspack)
#include <mspack.h>
// Assume simple XML parser header; for brevity, use custom parsing functions.
struct XSNHandler {
char* filepath;
char* manifest_content; // Raw XML string
};
struct XSNHandler* createXSNHandler(const char* filepath) {
struct XSNHandler* handler = malloc(sizeof(struct XSNHandler));
handler->filepath = strdup(filepath);
handler->manifest_content = NULL;
load(handler);
return handler;
}
void load(struct XSNHandler* handler) {
// Use libmspack to extract manifest.xsf
struct mscab_decompressor* cabd = mscab_decompressor_create();
struct mscabd_cabinet* cab = cabd->open(cabd, handler->filepath);
struct mscabd_file* file = cab->files;
while (file) {
if (strcmp(file->filename, "manifest.xsf") == 0) {
handler->manifest_content = malloc(file->length + 1);
cabd->extract(cabd, file, "temp_manifest.xsf"); // Extract to temp
FILE* f = fopen("temp_manifest.xsf", "r");
fread(handler->manifest_content, 1, file->length, f);
handler->manifest_content[file->length] = '\0';
fclose(f);
remove("temp_manifest.xsf");
break;
}
file = file->next;
}
cabd->close(cabd, cab);
mscab_decompressor_destroy(cabd);
}
void printProperties(struct XSNHandler* handler) {
if (!handler->manifest_content) return;
// Custom XML parsing: Search for attributes (simplified string search for demo)
printf("Properties:\n");
char* name = strstr(handler->manifest_content, "name=\"");
if (name) printf("- Form Name: %s\n", /* parse value */);
// Extend for other properties with string parsing or full XML lib...
}
void writeProperties(struct XSNHandler* handler, /* updates */) {
// Update content, repack CAB using libmspack compress
}
void destroyXSNHandler(struct XSNHandler* handler) {
free(handler->filepath);
free(handler->manifest_content);
free(handler);
}
// Usage example:
// struct XSNHandler* handler = createXSNHandler("example.xsn");
// printProperties(handler);
// destroyXSNHandler(handler);
Note: Full XML parsing and CAB repacking require additional library integration; this provides the structural framework.