Working with Custom XML Markup
Working with Custom XML Markup
This guide shows how to read and manage the custom XML data a Word document can carry alongside its visible content — data used to bind content controls, store application-specific metadata, or embed arbitrary package parts. Document.CustomXmlParts exposes document-level custom XML data, and Document.PackageCustomParts exposes package-level custom parts that are not custom XML specifically.
Custom XML Parts
CustomXmlPart represents one custom XML data island attached to the document — the same mechanism Word uses to back XML-mapped content controls. Each part has an Id, a Data byte array holding the raw XML, a DataChecksum, and a Schemas property (a CustomXmlSchemaCollection) listing the XML schemas associated with it. Document.CustomXmlParts returns a CustomXmlPartCollection: Add(part) attaches an existing CustomXmlPart, Add(id, xml) creates one directly from an id and XML string, GetById(id) retrieves a specific part, and RemoveAt(index)/Clear() remove parts. Both CustomXmlPart and CustomXmlPartCollection expose Clone() for duplicating custom XML data, for example when copying content between documents.
Custom XML Schemas
CustomXmlSchemaCollection, reached through CustomXmlPart.Schemas, lists the schema URIs associated with a custom XML part. It supports Add(value), Remove(name), RemoveAt(index), IndexOf(value), Clear(), and Clone(), alongside a Count property — schema URIs are tracked as plain strings rather than parsed schema objects.
Custom XML Properties
Separately from CustomXmlPart, CustomXmlProperty represents a single name/value XML property, constructed with CustomXmlProperty(name, uri, value) and exposing Name, Uri, and Value. CustomXmlPropertyCollection manages a set of these: Add(property) adds one, the indexer (e.g. properties["MyProp"]) looks one up by name and Contains(name) tests whether it’s present, IndexOfKey(name) returns its position, and Remove(name)/RemoveAt(index)/Clear() remove entries. SmartTag.Properties returns a CustomXmlPropertyCollection, which is how a legacy smart tag’s structured data is represented (see below).
Package-Level Custom Parts
Document.PackageCustomParts returns a CustomPartCollection of CustomPart objects — arbitrary parts stored in the OOXML package that aren’t custom XML data, such as parts added by other applications that touched the file. Each CustomPart has a Name, ContentType, RelationshipType, a Data byte array, and an IsExternal flag indicating whether the part is an external reference rather than embedded content. The collection supports Add(part), RemoveAt(index), Clear(), and Clone(), alongside Count.
Legacy Smart Tags
SmartTag is a node type (NodeType.SmartTag) representing a legacy Word smart tag wrapped around recognized text. A SmartTag is constructed with SmartTag(doc), and exposes Element (the recognizer element name) and Uri (the recognizer’s namespace), alongside Properties — a CustomXmlPropertyCollection holding the structured data the recognizer attached to the tagged text. Because SmartTag is a node, it also participates in the document tree like other nodes, supporting Accept(visitor), AcceptStart(visitor), and AcceptEnd(visitor) for DocumentVisitor-based traversal.
MarkupLevel
MarkupLevel is an enum — Unknown, Inline, Block, Row, Cell — describing the structural level in the document tree at which a markup element such as a structured document tag can occur.
Tips and Best Practices
- Use
CustomXmlPartCollection.GetById(id)rather than iterating the collection manually when you know the id of the part you need. - Read
CustomXmlPart.DataChecksumto detect whether the underlying XML data has changed without doing a full byte comparison. - Distinguish
Document.CustomXmlParts(custom XML data, often bound to content controls) fromDocument.PackageCustomParts(arbitrary non-XML package parts) — they serve different purposes and are stored separately. - When working with legacy documents that use smart tags, check
SmartTag.ElementandUritogether to identify which recognizer created the tag before relying on itsProperties. - Clone custom XML parts with
CustomXmlPart.Clone()(or the collection’sClone()) when copying data between documents rather than re-reading and re-adding the raw XML.
Common Issues
| Issue | Cause | Fix |
|---|---|---|
CustomXmlPartCollection.GetById(id) returns nothing usable | The id doesn’t match any part currently in Document.CustomXmlParts | Enumerate the collection to confirm the id, or add the part first with Add(id, xml) |
| Custom XML data appears unrelated to visible content controls | Content controls bind to custom XML via their own data-binding configuration, not automatically to every CustomXmlPart | Confirm which part a given content control is bound to rather than assuming a 1:1 relationship with Document.CustomXmlParts |
A package part added by another application isn’t found in CustomXmlParts | Non-XML package parts are exposed through Document.PackageCustomParts, not CustomXmlParts | Check PackageCustomParts (a CustomPartCollection) instead |
SmartTag.Properties is empty | Not every smart tag recognizer attaches structured properties | Check SmartTag.Element/Uri to confirm which recognizer created the tag before expecting specific properties |
FAQ
What’s the difference between CustomXmlPart and CustomXmlProperty?
CustomXmlPart is a whole XML data island (with a byte-array payload and associated schemas), reached through Document.CustomXmlParts. CustomXmlProperty is a single name/value pair, typically reached through SmartTag.Properties rather than directly from the document.
How do I add custom XML data to a document?
Call Document.CustomXmlParts.Add(id, xml) with an id string and the XML content, or construct a CustomXmlPart separately and pass it to Add(part).
What are package custom parts, and how are they different from custom XML parts?
Document.PackageCustomParts (a CustomPartCollection of CustomPart objects) holds arbitrary OOXML package parts that are not custom XML — each with a ContentType, RelationshipType, and raw Data. Document.CustomXmlParts is specifically for custom XML data islands.
What is a SmartTag?
SmartTag is a legacy Word feature representing text recognized and wrapped by a smart-tag recognizer. It’s a document node (NodeType.SmartTag) with an Element and Uri identifying the recognizer, and a Properties collection of CustomXmlProperty values the recognizer attached.
How do I copy custom XML data between documents?
Use CustomXmlPart.Clone() on the source part, then add the clone to the target document’s Document.CustomXmlParts with Add(part).
API Reference Summary
| Class/Method | Description |
|---|---|
CustomXmlPart | A single custom XML data island attached to a document |
Document.CustomXmlParts | The CustomXmlPartCollection of all custom XML parts on a document |
CustomXmlPartCollection.Add(id, xml) / GetById(id) | Add or retrieve a custom XML part by id |
CustomXmlSchemaCollection | Schema URIs associated with a CustomXmlPart |
CustomXmlProperty | A single name/value XML property |
CustomXmlPropertyCollection | A collection of CustomXmlProperty values, e.g. on SmartTag.Properties |
Document.PackageCustomParts | The CustomPartCollection of arbitrary non-XML OOXML package parts |
CustomPart | One package-level custom part with Name, ContentType, and raw Data |
SmartTag | Legacy node type wrapping text recognized by a smart-tag recognizer |
MarkupLevel | Enum describing where a markup element can occur in the document tree |