How to Work with Custom XML Markup in .NET

How to Work with Custom XML Markup in .NET

How to Work with Custom XML Markup in .NET

A Word document can carry custom XML data alongside its visible content — data used to bind content controls, store application-specific metadata, or embed parts added by another application. This guide shows how to read that data, add new custom XML parts, and inspect the legacy smart tags older documents may still contain, using CustomXmlPart, CustomXmlProperty, and SmartTag in Aspose.Words FOSS for .NET.


Step-by-Step Guide

Step 1: Read Custom XML Data From a Document

Document.CustomXmlParts returns a CustomXmlPartCollection — the same mechanism Word uses to back XML-mapped content controls. Iterate the collection, or call GetById(id) when you already know which part you need, to get a CustomXmlPart. Each part exposes Id, a Data byte array holding the raw XML, a DataChecksum for detecting whether the data has changed without a full byte comparison, and Schemas — a CustomXmlSchemaCollection listing the XML schemas associated with it.


Step 2: Add or Update a Custom XML Part

Call CustomXmlPartCollection.Add(id, xml) with an id string and the XML content to create a part directly, or construct a CustomXmlPart separately and pass it to Add(part). To remove data, use RemoveAt(index) on a specific position or Clear() to drop every part. When copying custom XML data between documents, use CustomXmlPart.Clone() (or the collection’s Clone()) on the source part rather than re-reading and re-adding the raw XML, then add the clone to the target document’s Document.CustomXmlParts.


Step 3: Manage the Schemas Associated With a Part

CustomXmlPart.Schemas reaches a CustomXmlSchemaCollection, which tracks the schema URIs associated with the part as plain strings rather than parsed schema objects. Use Add(value) to register a schema URI, Remove(name) or RemoveAt(index) to drop one, IndexOf(value) to locate one, and Clear() to remove them all. Count reports how many schema URIs are currently associated with the part.


Step 4: Work with Package-Level Custom Parts

Not every non-visible part in an OOXML package is custom XML. Document.PackageCustomParts returns a CustomPartCollection of CustomPart objects — arbitrary parts stored in the package, such as parts added by another application that touched the file. Each CustomPart has a Name, ContentType, RelationshipType, a Data byte array, and an IsExternal flag indicating whether it’s an external reference rather than embedded content. Add(part), RemoveAt(index), and Clear() manage the collection the same way as CustomXmlPartCollection. Check PackageCustomParts — not CustomXmlParts — when a part your document should carry isn’t showing up in the custom XML collection.


Step 5: Inspect Legacy Smart Tags and Their Properties

SmartTag is a node type (NodeType.SmartTag, constructed with SmartTag(doc)) representing a legacy Word smart tag wrapped around recognized text. Check Element and Uri together to identify which recognizer created the tag, then read Properties — a CustomXmlPropertyCollection — for the structured data that recognizer attached. Within a CustomXmlPropertyCollection, the indexer (e.g. properties["MyProp"]) or Contains(name) look up a specific property, IndexOfKey(name) returns its position, and Remove(name)/RemoveAt(index)/Clear() remove entries; each CustomXmlProperty is constructed with CustomXmlProperty(name, uri, value) and exposes Name, Uri, and Value. Because SmartTag derives from CompositeNode, it also participates in the document tree like other nodes, supporting Accept(visitor), AcceptStart(visitor), and AcceptEnd(visitor) for DocumentVisitor-based traversal.


Common Issues and Fixes

CustomXmlPartCollection.GetById(id) returns nothing usable. The id doesn’t match any part currently in Document.CustomXmlParts. Enumerate the collection to confirm the id is present, or add the part first with Add(id, xml).

A part added by another application isn’t found by iterating CustomXmlParts. Non-XML package parts are exposed through Document.PackageCustomParts, not CustomXmlParts. Check PackageCustomParts (a CustomPartCollection) instead.

SmartTag.Properties is empty even though the tag is clearly present. Not every smart tag recognizer attaches structured properties. Check SmartTag.Element and Uri to confirm which recognizer created the tag before assuming specific properties will be present.

Custom XML data doesn’t seem related to the content control it should be bound to. Content controls bind to custom XML through their own data-binding configuration, not automatically to every CustomXmlPart in Document.CustomXmlParts. Confirm which part a given content control is actually bound to rather than assuming a one-to-one relationship.


Frequently Asked Questions

How do I add custom XML data to a document?

Call Document.CustomXmlParts.Add(id, xml) with an id string and XML content, or construct a CustomXmlPart separately and pass it to Add(part).

What’s the difference between CustomXmlPart and CustomXmlProperty?

CustomXmlPart is a whole XML data island — a byte-array payload plus 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 copy custom XML data from one document to another?

Call Clone() on the source CustomXmlPart, then add the clone to the target document’s Document.CustomXmlParts with Add(part).

What is a SmartTag, and when would I encounter one?

SmartTag is a legacy Word feature representing text recognized and wrapped by a smart-tag recognizer — a document node (NodeType.SmartTag) with an Element and Uri identifying the recognizer, plus a Properties collection of CustomXmlProperty values. It shows up in documents that were authored or edited with smart tags enabled in older Word versions.

How do I know how many custom XML parts or package parts a document has?

Read Count on Document.CustomXmlParts (a CustomXmlPartCollection) or Document.PackageCustomParts (a CustomPartCollection) respectively.


See Also