Rethinking DITA "Custom" Attributes
To date I think I have been consistent in saying "You can't define attributes for individual elements in a way that is a conforming DITA specialization."
But in discussing this today with some colleagues I realized I have been too limited in my thinking. In particular, I now think that @base is an appropriate specialization base for any "custom" attribute and can be combined with constraint modules to limit the appearance of those attributes to specific element types.
If the initial requirement is, for example, "I want the attribute @foo on table" then I think you can make this a conforming @base specialization as follows:
1. Declare a normal attribute domain module for your new attribute, specializing it from @base:
me_fooAttDomain.ent: <!-- @foo attribute domain module: --> <!ENTITY % me_fooAtt-d-attribute "foo CDATA #IMPLIED"> <!ENTITY me_fooAtt-d-att "a(base foo)" > <!-- End of domain module -->
2. Define a constraint module that allows @foo on the elements you want it to be allowed on:
me_fooAttributeConstraint.mod: <!-- @foo attribute constraint module: --> <!ENTITY me_footAttTableOnly-constraints "(topic me_fooAttTableOnly-c)" > <!ATTLIST table foo CDATA #IMPLIED > <!-- End of constraint module. -->
3. In your shell, include the domain module but *do not* add it to the @base overrides (the not including it is a constraint and needs to be declared as such on the @domains attribute, which our separate constraint module will do for us):
4. In your shell, include the constraint module:
<!ENTITY % me_fooAtt-d-dec PUBLIC "urn:pubid:example.com:dita:attributes:me_fooAttDomain.ent" "me_fooAttDomain.ent" >%me_fooAtt-d-doc; ... <!-- Constraint: Not including @foo in base attribute extensions: --> <!ENTITY % base-attribute-extensions "" >
<!-- ============================================================= --> <!-- DOMAIN CONSTRAINT INTEGRATION --> <!-- ============================================================= --> <!ENTITY % me_fooAttributeConstraint.def PUBLIC "urn:pubid:example.com:dita:constraints:me_fooAttributeConstraint.mod" "me_fooAttributeConstraint.mod" >%me_fooAttributeConstraint.def;
5. In your shell, add the constraint domains contribution to the @domains attribute:
<!ENTITY included-domains "&concept-att; ... &me_footAttTableOnly-constraints; " >
You've now declared a specialization of @base but then constrained it to only be allowed on <table>, as defined in the separate constraint module.
The 1.3 specification says this about the @base attribute:
As long as your attribute's values will satisfy the requirement that "The attribute takes a space-delimited set of values." then your attributes will be conforming instances of @base.
An interesting implication of using @base is that normal generalization processing will convert @foo="bar" to base="foo(bar)". Which means you can also author @base attributes using that syntax (just as you can author @props using the same syntax, e.g. props="mycondition(myvalue)", which is equivalent to having a @props specialization named "@mycondition" with the value "myvalue"). In particular, this provides a standard way to interchange documents in terms of the OASIS-defined vocabulary without loss of information by generalizing specialized attributes to their @base and @props bases (which is part of the point of attribute specialization in the first place).
The result of all this is that you have an attribute this is a conforming specialization of @base and it's limited, via constraint, to only those places that you want to allow it. Your intent as a grammar designer is clear: I want this attribute to be limited to these element types.
If the constraint module isn't used (but the attribute domain is in the normal way), all your existing documents that have @foo on <table> will continue to be valid, which is one test for the correctness of a constraint. If they are generalized so @foo becomes base="foo(bar)" they will also continue to be valid.
So I reverse my earlier position on the appropriateness and conformance of element-type-specific attributes: the @base attribute combined with the constraint mechanism allows it without having to play any semantic tricks. Interchange is preserved through generalization, everyone is happy, and peace and prosperity reigns across the land.