Working with Custom XML Markup

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.DataChecksum to 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) from Document.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.Element and Uri together to identify which recognizer created the tag before relying on its Properties.
  • Clone custom XML parts with CustomXmlPart.Clone() (or the collection’s Clone()) when copying data between documents rather than re-reading and re-adding the raw XML.

Common Issues

IssueCauseFix
CustomXmlPartCollection.GetById(id) returns nothing usableThe id doesn’t match any part currently in Document.CustomXmlPartsEnumerate the collection to confirm the id, or add the part first with Add(id, xml)
Custom XML data appears unrelated to visible content controlsContent controls bind to custom XML via their own data-binding configuration, not automatically to every CustomXmlPartConfirm 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 CustomXmlPartsNon-XML package parts are exposed through Document.PackageCustomParts, not CustomXmlPartsCheck PackageCustomParts (a CustomPartCollection) instead
SmartTag.Properties is emptyNot every smart tag recognizer attaches structured propertiesCheck 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/MethodDescription
CustomXmlPartA single custom XML data island attached to a document
Document.CustomXmlPartsThe CustomXmlPartCollection of all custom XML parts on a document
CustomXmlPartCollection.Add(id, xml) / GetById(id)Add or retrieve a custom XML part by id
CustomXmlSchemaCollectionSchema URIs associated with a CustomXmlPart
CustomXmlPropertyA single name/value XML property
CustomXmlPropertyCollectionA collection of CustomXmlProperty values, e.g. on SmartTag.Properties
Document.PackageCustomPartsThe CustomPartCollection of arbitrary non-XML OOXML package parts
CustomPartOne package-level custom part with Name, ContentType, and raw Data
SmartTagLegacy node type wrapping text recognized by a smart-tag recognizer
MarkupLevelEnum describing where a markup element can occur in the document tree

See Also