Search code examples
c#linqopenxmlbookmarks

Defining correct ids for new bookmarks in OpenXML document


I'm writing a POC application in which I want to be able to dynamically create bookmarks in a Word document, based on various criteria.

So far I've managed to actually create and add BookmarkStart and BookmarkEnd elements, but I'm trying to figure out how the 'Id' property should be set.

The only bit of specification I could find in this regard is this sample from the MSDN for the BookmarkStart element:

id (Annotation Identifier)
Specifies a unique identifier for an annotation within a WordprocessingML document. The restrictions on the id attribute, if any, are defined by the parent XML element.
If this attribute is omitted, then the document is non-conformant.
[Example: Consider an annotation represented using the following WordprocessingML fragment:
<… w:id="1" … >

</…>
The id attribute specifies that the ID of the current annotation is 1. This value is used to uniquely identify this annotation within the document content. end example]
The possible values for this attribute are defined by the ST_DecimalNumber simple type (§17.18.10).

So, I understand that it needs to be a number, that it is mandatory, and that ids must be unique (duh!). Now, is it supposed to be unique only between bookmark elements, or between all elements defining an id? And how should I produce such an id? I'm thinking using Linq to get all ids as numeric values (integers? to me "Decimal" implies floating-point) and then adding one to the max but that seems a bit extreme.

My solution so far consists in the following function:

private static string ComputeNewId(OpenXmlElement root)
{
    return ((from b in root.Descendants<BookmarkStart>() select Decimal.Parse(b.Id)).Max() + 1).ToString();
}

So far it appears to be working, but I honestly have no idea if this is going to be any sort of reliable in the long run, so any additional information about this would be very welcome.

Thx all.


Solution

  • I'll try and answer each of your questions in turn:

    is it supposed to be unique only between bookmark elements, or between all elements defining an id?

    The Id needs to be unique only amongst BoookmarkStart elements. A BookmarkStart must have a corresponding BookmarkEnd with the same Id otherwise the document is non-compiant.

    §17.13.6.2 bookmarkStart states:

    This element specifies the start of a bookmark within a WordprocessingML document. This start marker is matched with the appropriately paired end marker by matching the value of the id attribute from the associated bookmarkEnd element.

    And how should I produce such an id?

    Taking the current largest Id and adding one is a sensible approach. You could potentially only find the max value once and store it from then on but that wouldn't make a huge difference compared to what you've already done I wouldn't have thought.

    integers? to me "Decimal" implies floating-point

    ST_DecimalNumber only allows whole numbers. I think decimal is a reference to the number being base 10 rather than hex or binary for example.

    From Section §17.18.10 (emphasis mine):

    This simple type specifies that its contents contain a whole decimal number (positive or negative), whose contents are interpreted based on the context of the parent XML element.

    It goes on to say:

    This simple type's contents are a restriction of the W3C XML Schema integer datatype.