Yaidom's extensibility even extends to support for XML dialects, such as the dialect of XBRL instances. See the class hierarchy below:
package eu.cdevreeze.yaidom.blogcode
import scala.BigDecimal
import scala.collection.immutable
import scala.reflect.classTag
import eu.cdevreeze.yaidom.core.EName
import eu.cdevreeze.yaidom.core.Path
import eu.cdevreeze.yaidom.core.QName
import eu.cdevreeze.yaidom.core.Scope
import eu.cdevreeze.yaidom.queryapi.ElemApi.anyElem
import eu.cdevreeze.yaidom.queryapi.HasENameApi.ToHasElemApi
import eu.cdevreeze.yaidom.queryapi.HasENameApi.withEName
import eu.cdevreeze.yaidom.queryapi.IsNavigable
import eu.cdevreeze.yaidom.queryapi.ScopedElemLike
import eu.cdevreeze.yaidom.queryapi.SubtypeAwareElemLike
import eu.cdevreeze.yaidom.indexed
import java.net.URI
object XbrlInstanceSupport {
/**
* XML element inside XBRL instance (or the entire XBRL instance itself). This API is immutable.
*
* The `SubtypeAwareElemApi` API is offered.
*
* Also note that the package-private constructor contains redundant data, in order to speed up (yaidom-based) querying.
*
* These XBRL instance elements are just an XBRL instance view on the underlying "indexed" element tree, and
* therefore do not know about the taxonomy describing the XBRL instance (other than the href to the DTS entrypoint).
*
* As a consequence, this model must recognize facts by only looking at the elements and their ancestry, without knowing
* anything about the substitution groups of the corresponding concept declarations. Fortunately, the XBRL instance
* schema (xbrl-instance-2003-12-31.xsd) and the specification of allowed XBRL tuple content are (almost) restrictive enough
* in order to recognize facts.
*
* It is even possible to easily distinguish between item facts and tuple facts, based on the presence or absence of the
* contextRef attribute. There is one complication, though, and that is nil item and tuple facts. Unfortunately, concept
* declarations in taxonomy schemas may have the nillable attribute set to true. This led to some clutter in the
* inheritance hierarchy for numeric item facts.
*
* Hence, regarding nil facts, the user of the API is responsible for keeping in mind that facts can indeed be nil facts
* (which facts are easy to filter away).
*
* @author Chris de Vreeze
*/
sealed class XbrliElem private[XbrlInstanceSupport] (
val indexedElem: indexed.Elem,
childElems: immutable.IndexedSeq[XbrliElem]) extends ScopedElemLike[XbrliElem] with IsNavigable[XbrliElem] with SubtypeAwareElemLike[XbrliElem] {
require(childElems.map(_.indexedElem) == indexedElem.findAllChildElems)
/**
* Very fast implementation of findAllChildElems, for fast querying
*/
final def findAllChildElems: immutable.IndexedSeq[XbrliElem] = childElems
final def resolvedName: EName = indexedElem.resolvedName
final def resolvedAttributes: immutable.Iterable[(EName, String)] = indexedElem.resolvedAttributes
final def qname: QName = indexedElem.qname
final def attributes: immutable.Iterable[(QName, String)] = indexedElem.attributes
final def scope: Scope = indexedElem.scope
final def text: String = indexedElem.text
final def findChildElemByPathEntry(entry: Path.Entry): Option[XbrliElem] =
childElems.find(e => e.localName == entry.elementName.localPart && e.indexedElem.path.lastEntry == entry)
final override def equals(other: Any): Boolean = other match {
case e: XbrliElem => indexedElem == e.indexedElem
case _ => false
}
final override def hashCode: Int = indexedElem.hashCode
}
/**
* XBRL instance.
*
* It does not check validity of the XBRL instance. Neither does it know about the DTS describing the XBRL instance.
* It does, however, contain the entrypoint URI(s) to the DTS.
*
* Without any knowledge about the DTS, this class only recognizes (item and tuple) facts by looking at the
* structure of the element and its ancestry. Attribute @contextRef is only allowed for item facts, and tuple facts can be
* recognized by looking at the "path" of the element.
*
* @author Chris de Vreeze
*/
final class XbrlInstance private[XbrlInstanceSupport] (
override val indexedElem: indexed.Elem,
childElems: immutable.IndexedSeq[XbrliElem]) extends XbrliElem(indexedElem, childElems) {
require(resolvedName == XbrliXbrlEName, s"Expected EName $XbrliXbrlEName but found $resolvedName")
val allContexts: immutable.IndexedSeq[XbrliContext] =
findAllChildElemsOfType(classTag[XbrliContext])
val allContextsById: Map[String, XbrliContext] =
allContexts.groupBy(_.id) mapValues (_.head)
val allUnits: immutable.IndexedSeq[XbrliUnit] =
findAllChildElemsOfType(classTag[XbrliUnit])
val allUnitsById: Map[String, XbrliUnit] =
allUnits.groupBy(_.id) mapValues (_.head)
val allTopLevelFacts: immutable.IndexedSeq[Fact] =
findAllChildElemsOfType(classTag[Fact])
val allTopLevelItems: immutable.IndexedSeq[ItemFact] =
findAllChildElemsOfType(classTag[ItemFact])
val allTopLevelTuples: immutable.IndexedSeq[TupleFact] =
findAllChildElemsOfType(classTag[TupleFact])
val allTopLevelFactsByEName: Map[EName, immutable.IndexedSeq[Fact]] =
allTopLevelFacts groupBy (_.resolvedName)
val allTopLevelItemsByEName: Map[EName, immutable.IndexedSeq[ItemFact]] =
allTopLevelItems groupBy (_.resolvedName)
val allTopLevelTuplesByEName: Map[EName, immutable.IndexedSeq[TupleFact]] =
allTopLevelTuples groupBy (_.resolvedName)
def filterTopLevelFacts(p: Fact => Boolean): immutable.IndexedSeq[Fact] = {
filterChildElemsOfType(classTag[Fact])(p)
}
def filterTopLevelItems(p: ItemFact => Boolean): immutable.IndexedSeq[ItemFact] = {
filterChildElemsOfType(classTag[ItemFact])(p)
}
def filterTopLevelTuples(p: TupleFact => Boolean): immutable.IndexedSeq[TupleFact] = {
filterChildElemsOfType(classTag[TupleFact])(p)
}
def findAllFacts: immutable.IndexedSeq[Fact] = {
findAllElemsOfType(classTag[Fact])
}
def findAllItems: immutable.IndexedSeq[ItemFact] = {
findAllElemsOfType(classTag[ItemFact])
}
def findAllTuples: immutable.IndexedSeq[TupleFact] = {
findAllElemsOfType(classTag[TupleFact])
}
def filterFacts(p: Fact => Boolean): immutable.IndexedSeq[Fact] = {
filterElemsOfType(classTag[Fact])(p)
}
def filterItems(p: ItemFact => Boolean): immutable.IndexedSeq[ItemFact] = {
filterElemsOfType(classTag[ItemFact])(p)
}
def filterTuples(p: TupleFact => Boolean): immutable.IndexedSeq[TupleFact] = {
filterElemsOfType(classTag[TupleFact])(p)
}
def findAllSchemaRefs: immutable.IndexedSeq[SchemaRef] = {
findAllChildElemsOfType(classTag[SchemaRef])
}
def findAllLinkbaseRefs: immutable.IndexedSeq[LinkbaseRef] = {
findAllChildElemsOfType(classTag[LinkbaseRef])
}
def findAllRoleRefs: immutable.IndexedSeq[RoleRef] = {
findAllChildElemsOfType(classTag[RoleRef])
}
def findAllArcroleRefs: immutable.IndexedSeq[ArcroleRef] = {
findAllChildElemsOfType(classTag[ArcroleRef])
}
def findAllFootnoteLinks: immutable.IndexedSeq[FootnoteLink] = {
findAllChildElemsOfType(classTag[FootnoteLink])
}
}
/**
* SchemaRef in an XBRL instance
*
* @author Chris de Vreeze
*/
final class SchemaRef private[XbrlInstanceSupport] (
override val indexedElem: indexed.Elem,
childElems: immutable.IndexedSeq[XbrliElem]) extends XbrliElem(indexedElem, childElems) {
require(resolvedName == LinkSchemaRefEName, s"Expected EName $LinkSchemaRefEName but found $resolvedName")
}
/**
* LinkbaseRef in an XBRL instance
*
* @author Chris de Vreeze
*/
final class LinkbaseRef private[XbrlInstanceSupport] (
override val indexedElem: indexed.Elem,
childElems: immutable.IndexedSeq[XbrliElem]) extends XbrliElem(indexedElem, childElems) {
require(resolvedName == LinkLinkbaseRefEName, s"Expected EName $LinkLinkbaseRefEName but found $resolvedName")
}
/**
* RoleRef in an XBRL instance
*
* @author Chris de Vreeze
*/
final class RoleRef private[XbrlInstanceSupport] (
override val indexedElem: indexed.Elem,
childElems: immutable.IndexedSeq[XbrliElem]) extends XbrliElem(indexedElem, childElems) {
require(resolvedName == LinkRoleRefEName, s"Expected EName $LinkRoleRefEName but found $resolvedName")
}
/**
* ArcroleRef in an XBRL instance
*
* @author Chris de Vreeze
*/
final class ArcroleRef private[XbrlInstanceSupport] (
override val indexedElem: indexed.Elem,
childElems: immutable.IndexedSeq[XbrliElem]) extends XbrliElem(indexedElem, childElems) {
require(resolvedName == LinkArcroleRefEName, s"Expected EName $LinkArcroleRefEName but found $resolvedName")
}
/**
* Context in an XBRL instance
*
* @author Chris de Vreeze
*/
final class XbrliContext private[XbrlInstanceSupport] (
override val indexedElem: indexed.Elem,
childElems: immutable.IndexedSeq[XbrliElem]) extends XbrliElem(indexedElem, childElems) {
require(resolvedName == XbrliContextEName, s"Expected EName $XbrliContextEName but found $resolvedName")
def id: String = attribute(IdEName)
def entity: Entity = {
getChildElemOfType(classTag[Entity])(anyElem)
}
def period: Period = {
getChildElemOfType(classTag[Period])(anyElem)
}
def scenarioOption: Option[Scenario] = {
findChildElemOfType(classTag[Scenario])(anyElem)
}
}
/**
* Unit in an XBRL instance
*
* @author Chris de Vreeze
*/
final class XbrliUnit private[XbrlInstanceSupport] (
override val indexedElem: indexed.Elem,
childElems: immutable.IndexedSeq[XbrliElem]) extends XbrliElem(indexedElem, childElems) {
require(resolvedName == XbrliUnitEName, s"Expected EName $XbrliUnitEName but found $resolvedName")
def id: String = attribute(IdEName)
def measures: immutable.IndexedSeq[EName] = {
filterChildElems(XbrliMeasureEName) map (e => e.textAsResolvedQName)
}
def divide: Divide = {
getChildElemOfType(classTag[Divide])(anyElem)
}
}
/**
* Item or tuple fact in an XBRL instance, either top-level or nested (and either non-nil or nil)
*
* @author Chris de Vreeze
*/
abstract class Fact private[XbrlInstanceSupport] (
override val indexedElem: indexed.Elem,
childElems: immutable.IndexedSeq[XbrliElem]) extends XbrliElem(indexedElem, childElems) {
def isTopLevel: Boolean = indexedElem.path.entries.size == 1
def isNil: Boolean = attributeOption(XsiNilEName) == Some("true")
}
/**
* Item fact in an XBRL instance, either top-level or nested (and either non-nil or nil)
*
* @author Chris de Vreeze
*/
abstract class ItemFact private[XbrlInstanceSupport] (
override val indexedElem: indexed.Elem,
childElems: immutable.IndexedSeq[XbrliElem]) extends Fact(indexedElem, childElems) {
require(attributeOption(ContextRefEName).isDefined, s"Expected attribute $ContextRefEName")
def contextRef: String = attribute(ContextRefEName)
}
/**
* Non-numeric item fact in an XBRL instance, either top-level or nested (and either non-nil or nil)
*
* @author Chris de Vreeze
*/
final class NonNumericItemFact private[XbrlInstanceSupport] (
override val indexedElem: indexed.Elem,
childElems: immutable.IndexedSeq[XbrliElem]) extends ItemFact(indexedElem, childElems) {
require(attributeOption(UnitRefEName).isEmpty, s"Expected no attribute $UnitRefEName")
}
/**
* Numeric item fact in an XBRL instance, either top-level or nested (and either non-nil or nil)
*
* @author Chris de Vreeze
*/
abstract class NumericItemFact private[XbrlInstanceSupport] (
override val indexedElem: indexed.Elem,
childElems: immutable.IndexedSeq[XbrliElem]) extends ItemFact(indexedElem, childElems) {
require(attributeOption(UnitRefEName).isDefined, s"Expected attribute $UnitRefEName")
def unitRef: String = attribute(UnitRefEName)
}
/**
* Nil numeric item fact in an XBRL instance, either top-level or nested
*
* @author Chris de Vreeze
*/
final class NilNumericItemFact private[XbrlInstanceSupport] (
override val indexedElem: indexed.Elem,
childElems: immutable.IndexedSeq[XbrliElem]) extends NumericItemFact(indexedElem, childElems) {
require(isNil, s"Expected nil numeric item fact")
}
/**
* Non-nil non-fraction numeric item fact in an XBRL instance, either top-level or nested
*
* @author Chris de Vreeze
*/
final class NonNilNonFractionNumericItemFact private[XbrlInstanceSupport] (
override val indexedElem: indexed.Elem,
childElems: immutable.IndexedSeq[XbrliElem]) extends NumericItemFact(indexedElem, childElems) {
require(!isNil, s"Expected non-nil numeric item fact")
def precisionOption: Option[String] = attributeOption(PrecisionEName)
def decimalsOption: Option[String] = attributeOption(DecimalsEName)
}
/**
* Non-nil fraction item fact in an XBRL instance, either top-level or nested
*
* @author Chris de Vreeze
*/
final class NonNilFractionItemFact private[XbrlInstanceSupport] (
override val indexedElem: indexed.Elem,
childElems: immutable.IndexedSeq[XbrliElem]) extends NumericItemFact(indexedElem, childElems) {
require(!isNil, s"Expected non-nil numeric item fact")
require(findAllChildElems.map(_.resolvedName).toSet == Set(XbrliNumeratorEName, XbrliDenominatorEName))
def numerator: BigDecimal = {
val s = getChildElem(XbrliNumeratorEName).text
BigDecimal(s)
}
def denominator: BigDecimal = {
val s = getChildElem(XbrliDenominatorEName).text
BigDecimal(s)
}
}
/**
* Tuple fact in an XBRL instance, either top-level or nested (and either non-nil or nil)
*
* @author Chris de Vreeze
*/
final class TupleFact private[XbrlInstanceSupport] (
override val indexedElem: indexed.Elem,
childElems: immutable.IndexedSeq[XbrliElem]) extends Fact(indexedElem, childElems) {
def findAllChildFacts: immutable.IndexedSeq[Fact] = {
findAllChildElemsOfType(classTag[Fact])
}
def findAllFacts: immutable.IndexedSeq[Fact] = {
findAllElemsOfType(classTag[Fact])
}
def filterChildFacts(p: Fact => Boolean): immutable.IndexedSeq[Fact] = {
filterChildElemsOfType(classTag[Fact])(p)
}
def filterFacts(p: Fact => Boolean): immutable.IndexedSeq[Fact] = {
filterElemsOfType(classTag[Fact])(p)
}
}
/**
* FootnoteLink in an XBRL instance
*
* @author Chris de Vreeze
*/
final class FootnoteLink private[XbrlInstanceSupport] (
override val indexedElem: indexed.Elem,
childElems: immutable.IndexedSeq[XbrliElem]) extends XbrliElem(indexedElem, childElems) {
require(resolvedName == LinkFootnoteLinkEName, s"Expected EName $LinkFootnoteLinkEName but found $resolvedName")
}
/**
* Entity in an XBRL instance context
*
* @author Chris de Vreeze
*/
final class Entity private[XbrlInstanceSupport] (
override val indexedElem: indexed.Elem,
childElems: immutable.IndexedSeq[XbrliElem]) extends XbrliElem(indexedElem, childElems) {
require(resolvedName == XbrliEntityEName, s"Expected EName $XbrliEntityEName but found $resolvedName")
def identifier: Identifier = {
getChildElemOfType(classTag[Identifier])(anyElem)
}
def segmentOption: Option[Segment] = {
findChildElemOfType(classTag[Segment])(anyElem)
}
}
/**
* Period in an XBRL instance context
*
* TODO sub-traits
*
* @author Chris de Vreeze
*/
final class Period private[XbrlInstanceSupport] (
override val indexedElem: indexed.Elem,
childElems: immutable.IndexedSeq[XbrliElem]) extends XbrliElem(indexedElem, childElems) {
require(resolvedName == XbrliPeriodEName, s"Expected EName $XbrliPeriodEName but found $resolvedName")
def isInstant: Boolean = {
findChildElem(XbrliInstantEName).isDefined
}
def isFiniteDuration: Boolean = {
findChildElem(XbrliStartDateEName).isDefined
}
def isForever: Boolean = {
findChildElem(XbrliForeverEName).isDefined
}
}
/**
* Scenario in an XBRL instance context
*
* @author Chris de Vreeze
*/
final class Scenario private[XbrlInstanceSupport] (
override val indexedElem: indexed.Elem,
childElems: immutable.IndexedSeq[XbrliElem]) extends XbrliElem(indexedElem, childElems) {
require(resolvedName == XbrliScenarioEName, s"Expected EName $XbrliScenarioEName but found $resolvedName")
}
/**
* Segment in an XBRL instance context entity
*
* @author Chris de Vreeze
*/
final class Segment private[XbrlInstanceSupport] (
override val indexedElem: indexed.Elem,
childElems: immutable.IndexedSeq[XbrliElem]) extends XbrliElem(indexedElem, childElems) {
require(resolvedName == XbrliSegmentEName, s"Expected EName $XbrliSegmentEName but found $resolvedName")
}
/**
* Identifier in an XBRL instance context entity
*
* @author Chris de Vreeze
*/
final class Identifier private[XbrlInstanceSupport] (
override val indexedElem: indexed.Elem,
childElems: immutable.IndexedSeq[XbrliElem]) extends XbrliElem(indexedElem, childElems) {
require(resolvedName == XbrliIdentifierEName, s"Expected EName $XbrliIdentifierEName but found $resolvedName")
}
/**
* Divide in an XBRL instance unit
*
* @author Chris de Vreeze
*/
final class Divide private[XbrlInstanceSupport] (
override val indexedElem: indexed.Elem,
childElems: immutable.IndexedSeq[XbrliElem]) extends XbrliElem(indexedElem, childElems) {
require(resolvedName == XbrliDivideEName, s"Expected EName $XbrliDivideEName but found $resolvedName")
def numerator: immutable.IndexedSeq[EName] = {
val unitNumerator = getChildElem(XbrliUnitNumeratorEName)
val result = unitNumerator.filterChildElems(XbrliMeasureEName).map(e => e.textAsResolvedQName)
result
}
def denominator: immutable.IndexedSeq[EName] = {
val unitDenominator = getChildElem(XbrliUnitDenominatorEName)
val result = unitDenominator.filterChildElems(XbrliMeasureEName).map(e => e.textAsResolvedQName)
result
}
}
object XbrliElem {
/**
* Expensive method to create an XbrliElem tree
*/
def apply(elem: indexed.Elem): XbrliElem = {
// Recursive calls
val childElems = elem.findAllChildElems.map(e => apply(e))
apply(elem, childElems)
}
private[XbrlInstanceSupport] def apply(elem: indexed.Elem, childElems: immutable.IndexedSeq[XbrliElem]): XbrliElem = elem.resolvedName match {
case XbrliXbrlEName => new XbrlInstance(elem, childElems)
case LinkSchemaRefEName => new SchemaRef(elem, childElems)
case LinkLinkbaseRefEName => new LinkbaseRef(elem, childElems)
case LinkRoleRefEName => new RoleRef(elem, childElems)
case LinkArcroleRefEName => new ArcroleRef(elem, childElems)
case XbrliContextEName => new XbrliContext(elem, childElems)
case XbrliUnitEName => new XbrliUnit(elem, childElems)
case LinkFootnoteLinkEName => new FootnoteLink(elem, childElems)
case XbrliEntityEName => new Entity(elem, childElems)
case XbrliPeriodEName => new Period(elem, childElems)
case XbrliScenarioEName => new Scenario(elem, childElems)
case XbrliSegmentEName => new Segment(elem, childElems)
case XbrliIdentifierEName => new Identifier(elem, childElems)
case XbrliDivideEName => new Divide(elem, childElems)
case _ if Fact.accepts(elem) => Fact(elem, childElems)
case _ => new XbrliElem(elem, childElems)
}
}
object XbrlInstance {
def apply(elem: indexed.Elem): XbrlInstance = {
require(elem.resolvedName == XbrliXbrlEName)
XbrliElem.apply(elem).asInstanceOf[XbrlInstance]
}
}
object Fact {
def accepts(elem: indexed.Elem): Boolean = ItemFact.accepts(elem) || TupleFact.accepts(elem)
private[XbrlInstanceSupport] def apply(elem: indexed.Elem, childElems: immutable.IndexedSeq[XbrliElem]): Fact =
if (ItemFact.accepts(elem)) ItemFact(elem, childElems) else TupleFact(elem, childElems)
def isFactPath(path: Path): Boolean = {
!path.isRoot &&
!Set(Option(LinkNs), Option(XbrliNs)).contains(path.firstEntry.elementName.namespaceUriOption)
}
}
object ItemFact {
def accepts(elem: indexed.Elem): Boolean = {
Fact.isFactPath(elem.path) &&
elem.attributeOption(ContextRefEName).isDefined
}
private[XbrlInstanceSupport] def apply(elem: indexed.Elem, childElems: immutable.IndexedSeq[XbrliElem]): ItemFact = {
require(Fact.isFactPath(elem.path))
require(elem.attributeOption(ContextRefEName).isDefined)
val unitRefOption = elem.attributeOption(UnitRefEName)
if (unitRefOption.isEmpty) new NonNumericItemFact(elem, childElems)
else {
if (elem.attributeOption(XsiNilEName) == Some("true"))
new NilNumericItemFact(elem, childElems)
else if (elem.findChildElem(withEName(XbrliNumeratorEName)).isDefined)
new NonNilFractionItemFact(elem, childElems)
else
new NonNilNonFractionNumericItemFact(elem, childElems)
}
}
}
object TupleFact {
def accepts(elem: indexed.Elem): Boolean = {
Fact.isFactPath(elem.path) &&
elem.attributeOption(ContextRefEName).isEmpty
}
private[XbrlInstanceSupport] def apply(elem: indexed.Elem, childElems: immutable.IndexedSeq[XbrliElem]): TupleFact = {
require(Fact.isFactPath(elem.path))
require(elem.attributeOption(ContextRefEName).isEmpty)
new TupleFact(elem, childElems)
}
}
val XbrliNs = "http://www.xbrl.org/2003/instance"
val LinkNs = "http://www.xbrl.org/2003/linkbase"
val XmlNs = "http://www.w3.org/XML/1998/namespace"
val XsiNs = "http://www.w3.org/2001/XMLSchema-instance"
val XbrldiNs = "http://xbrl.org/2006/xbrldi"
val XbrliXbrlEName = EName(XbrliNs, "xbrl")
val XbrliContextEName = EName(XbrliNs, "context")
val XbrliUnitEName = EName(XbrliNs, "unit")
val XbrliEntityEName = EName(XbrliNs, "entity")
val XbrliPeriodEName = EName(XbrliNs, "period")
val XbrliScenarioEName = EName(XbrliNs, "scenario")
val XbrliIdentifierEName = EName(XbrliNs, "identifier")
val XbrliSegmentEName = EName(XbrliNs, "segment")
val XbrliInstantEName = EName(XbrliNs, "instant")
val XbrliStartDateEName = EName(XbrliNs, "startDate")
val XbrliEndDateEName = EName(XbrliNs, "endDate")
val XbrliForeverEName = EName(XbrliNs, "forever")
val XbrliMeasureEName = EName(XbrliNs, "measure")
val XbrliDivideEName = EName(XbrliNs, "divide")
val XbrliNumeratorEName = EName(XbrliNs, "numerator")
val XbrliDenominatorEName = EName(XbrliNs, "denominator")
val XbrliUnitNumeratorEName = EName(XbrliNs, "unitNumerator")
val XbrliUnitDenominatorEName = EName(XbrliNs, "unitDenominator")
val LinkSchemaRefEName = EName(LinkNs, "schemaRef")
val LinkLinkbaseRefEName = EName(LinkNs, "linkbaseRef")
val LinkRoleRefEName = EName(LinkNs, "roleRef")
val LinkArcroleRefEName = EName(LinkNs, "arcroleRef")
val LinkFootnoteLinkEName = EName(LinkNs, "footnoteLink")
val XmlLangEName = EName(XmlNs, "lang")
val XsiNilEName = EName(XsiNs, "nil")
val IdEName = EName("id")
val ContextRefEName = EName("contextRef")
val UnitRefEName = EName("unitRef")
val PrecisionEName = EName("precision")
val DecimalsEName = EName("decimals")
}