:books: Add doc.

:books: Add doc.

jsoniq version "1.0";
module namespace data-source-wrapper = "http://28.io/modules/xbrl/data-source-wrapper";

import module namespace config = "http://apps.28.io/config";
import module namespace mongo-wrapper = "http://28.io/modules/xbrl/mongo-wrapper";

(:~
 :
Count how many objects a collection contains.

 :
 : @param $collection the name of a collection.
 :
 : @return the number of objects in this collection.
 :)
declare function data-source-wrapper:count(
    $collection as string
) as integer {
    switch($config:query-db.category)
    case "MongoDB" return mongo-wrapper:count($collection)
    default return ()
};

(:~
 :
Filters the objects in a collection.

 :
The filter format is as follows.

 :
A filter query consists of a hierarchy of nested objects, the keys of
 : which MUST NOT contain the dollar symbol.

 :
The leaves of this object hierarchy MUST be one of the tree:

 :

 :
An atomic ("exact match").
 :
An array of atomics ("one-of-these-values match").
 :
The exact object { "$exists" : true } ("must-exist match").
 :

 :
The semantics of a filter query is that it performs a
 : conjunction on the filters done on all possible paths.

 :
For example, with only atomics as leafs to keep it simple:

 :

 : {
 :   "Aspects" : {
 :     "xbrl:Concept" : "us-gaap:Assets",
 :     "xbrl:Entity" : "4962"
 :   },
 :   "Value" : 3
 : }
 :

 :
 :
filters for facts $f that satisfy all of the following:

 :

 :
$f.Aspects."xbrl:Concept" eq "us-gaap:Assets"
 :
$f.Aspects."xbrl:Entity" eq "4962"
 :
$f.Value eq 3
 :

 :
If an atomic $a is used as a leaf, with path A.B.C, the filter of this
 : path is: $f.A.B.C eq $a

 :
If an array $a is used as a leaf, with path A.B.C, the filter of this path
 : is: $f.A.B.C = $a[]

 :
If { "$exists" : true } is used as a leaf, with path A.B.C, the filter of
 : this path is: exists($f.A.B.C)

 :
 :
Finally, it also allowed to wrap several filtering queries as specified
 : above in a disjunctive close, in an array associated with the key "$or":

 :

 : {
 :   "$or" : [ <query1>, <query2>, ... ]
 : }
 :

 :
 : @param $collection the name of a collection.
 : @param $query a filter query.
 :
 : @return the number of objects in this collection.
 :)
declare function data-source-wrapper:find(
    $collection as string,
    $query as object
) as object()*
{
  switch($config:query-db.category)
  case "MongoDB" return mongo-wrapper:find($collection, $query)
  default return ()
};

(:~
 :
Filters and projects the objects in a collection.

 :
The filter format is as described in the arity-2 variant of this
 : function.

 :
 : @param $collection the name of a collection.
 : @param $query a filter query.
 : @param $projection a projection (MongoDB-like).
 :
 : @return the number of objects in this collection.
 :)
declare function data-source-wrapper:find(
    $collection as string,
    $query as object,
    $projection as object
) as object()*
{
  switch($config:query-db.category)
  case "MongoDB" return mongo-wrapper:find($collection, $query, $projection)
  default return ()
};

declare function data-source-wrapper:text-search(
    $collection as string,
    $query as object) as object*
{
  switch($config:query-db.category)
  case "MongoDB" return mongo-wrapper:run-cmd-deterministic(
    {|
      { "text" : $collection },
      $query
    |}).results[].obj
  default return ()
};

declare function data-source-wrapper:connection() as anyURI?
{
  switch($config:query-db.category)
  case "MongoDB" return mongo-wrapper:connection()
  default return ()
};

jsoniq version "1.0";
module namespace data-source-wrapper = "http://28.io/modules/xbrl/data-source-wrapper";

import module namespace config = "http://apps.28.io/config";
import module namespace mongo-wrapper = "http://28.io/modules/xbrl/mongo-wrapper";

(:~
 :
Count how many objects a collection contains.

 :
 : @param $collection the name of a collection.
 :
 : @return the number of objects in this collection.
 :)
declare function data-source-wrapper:count(
    $collection as string
) as integer {
    switch($config:query-db.category)
    case "MongoDB" return mongo-wrapper:count($collection)
    default return ()
};

(:~
 :
Filters the objects in a collection.

 :
The filter format is as follows.

 :
A filter query consists of a hierarchy of nested objects, the keys of
 : which MUST NOT contain the dollar symbol.

 :
The leaves of this object hierarchy MUST be one of the tree:

 :

 :
An atomic ("exact match").
 :
An array of atomics ("one-of-these-values match").
 :
The exact object { "$exists" : true } ("must-exist match").
 :

 :
The semantics of a filter query is that it performs a
 : conjunction on the filters done on all possible paths.

 :
For example, with only atomics as leafs to keep it simple:

 :

 : {
 :   "Aspects" : {
 :     "xbrl:Concept" : "us-gaap:Assets",
 :     "xbrl:Entity" : "4962"
 :   },
 :   "Value" : 3
 : }
 :

 :
 :
filters for facts $f that satisfy all of the following:

 :

 :
$f.Aspects."xbrl:Concept" eq "us-gaap:Assets"
 :
$f.Aspects."xbrl:Entity" eq "4962"
 :
$f.Value eq 3
 :

 :
If an atomic $a is used as a leaf, with path A.B.C, the filter of this
 : path is: $f.A.B.C eq $a

 :
If an array $a is used as a leaf, with path A.B.C, the filter of this path
 : is: $f.A.B.C = $a[]

 :
If { "$exists" : true } is used as a leaf, with path A.B.C, the filter of
 : this path is: exists($f.A.B.C)

 :
 :
Finally, it also allowed to wrap several filtering queries as specified
 : above in a disjunctive close, in an array associated with the key "$or":

 :

 : {
 :   "$or" : [ <query1>, <query2>, ... ]
 : }
 :

 :
 : @param $collection the name of a collection.
 : @param $query a filter query.
 :
 : @return the number of objects in this collection.
 :)
declare function data-source-wrapper:find(
    $collection as string,
    $query as object
) as object()*
{
  switch($config:query-db.category)
  case "MongoDB" return mongo-wrapper:find($collection, $query)
  default return ()
};

declare function data-source-wrapper:find(
    $collection as string,
    $query as object,
    $projection as object
) as object()*
{
  switch($config:query-db.category)
  case "MongoDB" return mongo-wrapper:find($collection, $query, $projection)
  default return ()
};

declare function data-source-wrapper:text-search(
    $collection as string,
    $query as object) as object*
{
  switch($config:query-db.category)
  case "MongoDB" return mongo-wrapper:run-cmd-deterministic(
    {|
      { "text" : $collection },
      $query
    |}).results[].obj
  default return ()
};

declare function data-source-wrapper:connection() as anyURI?
{
  switch($config:query-db.category)
  case "MongoDB" return mongo-wrapper:connection()
  default return ()
};


:lipstick: Simplify code.

:lipstick: Simplify code.

jsoniq version "1.0";
(:
 : Copyright 2015 28msec Inc.
 :)

(:~
 :
This module provides functionality for retrieving labels.

 :
 : @author Federico Cavalieri, Ghislain Fourny
 :)
module namespace labels = "http://28.io/modules/xbrl/labels";

import module namespace concepts = "http://28.io/modules/xbrl/concepts";
import module namespace entities = "http://28.io/modules/xbrl/entities";

declare namespace xbrli = "http://www.xbrl.org/2003/instance";
declare namespace xlink = "http://www.w3.org/1999/xlink";

declare namespace ver = "http://zorba.io/options/versioning";
declare option ver:module-version "1.0";

(:~
 : A helper variable holding the default language ("en-US")
 :)
declare variable $labels:AMERICAN_ENGLISH as xs:string := "en-US";

(:~
 : The standard label role.
 :)
declare variable $labels:STANDARD_LABEL_ROLE as xs:string :=
    "http://www.xbrl.org/2003/role/label";

(:~
 : The verbose label role.
 :)
declare variable $labels:VERBOSE_LABEL_ROLE as xs:string :=
    "http://www.xbrl.org/2003/role/verboseLabel";

declare variable $labels:standard-concepts as object* :=
(
    {
      Name: "xbrl:Concept",
      Label: "Concept [Axis]",
      Kind: "Dimension",
      IsNillable: true,
      IsAbstract: true,
      PeriodType: "duration",
      SubstitutionGroup: "xbrldt:dimensionItem",
      DataType: "nonnum:domainItemType",
      BaseType: "string",
      ClosestSchemaBuiltinType: "xs:string",
      IsTextBlock: false,
      Labels: [
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "fr",
          Value: "Concept [Axe]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "de",
          Value: "Konzept [Achse]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "en-us",
          Value: "Concept [Axis]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "ja",
          Value: "項目(Concept)"
        }
      ]
    },
    {
      Name: "xbrl:Period",
      Label: "Period [Axis]",
      Kind: "Dimension",
      IsNillable: true,
      IsAbstract: true,
      PeriodType: "duration",
      SubstitutionGroup: "xbrldt:dimensionItem",
      DataType: "nonnum:domainItemType",
      BaseType: "string",
      ClosestSchemaBuiltinType: "xs:string",
      IsTextBlock: false,
      Labels: [
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "fr",
          Value: "Période [Axe]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "en-us",
          Value: "Period [Axis]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "de",
          Value: "Periode [Achse]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "ja",
          Value: "期間(Period)"
        }
      ]
    },
    {
      Name: "xbrl:Entity",
      Label: "Entity [Axis]",
      Kind: "Dimension",
      IsNillable: true,
      IsAbstract: true,
      PeriodType: "duration",
      SubstitutionGroup: "xbrldt:dimensionItem",
      DataType: "nonnum:domainItemType",
      BaseType: "string",
      ClosestSchemaBuiltinType: "xs:string",
      IsTextBlock: false,
      Labels: [
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "de",
          Value: "Entität [Achse]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "fr",
          Value: "Entité [Axe]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "en-us",
          Value: "Reporting Entity [Axis]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "ja",
          Value: "企業名(Entity)"
        }
      ]
    },
    {
      Name: "xbrl28:Archive",
      Label: "Archiv [Achse]",
      Kind: "Dimension",
      IsNillable: true,
      IsAbstract: true,
      PeriodType: "duration",
      SubstitutionGroup: "xbrldt:dimensionItem",
      DataType: "nonnum:domainItemType",
      BaseType: "string",
      ClosestSchemaBuiltinType: "xs:string",
      IsTextBlock: false,
      Labels: [
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "fr",
          Value: "Archive [Axe]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "de",
          Value: "Archiv [Achse]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "en-us",
          Value: "Archive [Axis]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "ja",
          Value: "ファイル(Archive)"
        }
      ]
    },
    {
      Name: "fsa:FiscalYear",
      Label: "Fiscal Year [Axis]",
      Kind: "Dimension",
      IsNillable: true,
      IsAbstract: true,
      PeriodType: "duration",
      SubstitutionGroup: "xbrldt:dimensionItem",
      DataType: "nonnum:domainItemType",
      BaseType: "string",
      ClosestSchemaBuiltinType: "xs:string",
      IsTextBlock: false,
      Labels: [
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "fr",
          Value: "Année fiscale [Axe]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "de",
          Value: "Steuerjahr [Achse]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "ja",
          Value: "会計年度(Fiscal Year)"
        }
      ]
    },
    {
      Name: "fsa:FiscalPeriod",
      Label: "Fiscal Period [Axis]",
      Kind: "Dimension",
      IsNillable: true,
      IsAbstract: true,
      PeriodType: "duration",
      SubstitutionGroup: "xbrldt:dimensionItem",
      DataType: "nonnum:domainItemType",
      BaseType: "string",
      ClosestSchemaBuiltinType: "xs:string",
      IsTextBlock: false,
      Labels: [
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "ja",
          Value: "会計期間(Fiscal Period)"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "en-us",
          Value: "Fiscal Period [Axis]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "fr",
          Value: "Période fiscal [Axe]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "de",
          Value: "Steuerperiode [Achse]"
        }
      ]
    },
    {
      Name: "fsa:FiscalPeriodType",
      Label: "Fiscal Period Type [Axis]",
      Kind: "Dimension",
      IsNillable: true,
      IsAbstract: true,
      PeriodType: "duration",
      SubstitutionGroup: "xbrldt:dimensionItem",
      DataType: "nonnum:domainItemType",
      BaseType: "string",
      ClosestSchemaBuiltinType: "xs:string",
      IsTextBlock: false,
      Labels: [
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "ja",
          Value: "会計期間タイプ(Fiscal Period Type)"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "en-us",
          Value: "Fiscal Period Type [Axis]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "fr",
          Value: "Type de période fiscale [Axe]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "de",
          Value: "Steuerperiodeart [Achse]"
        }
      ]
    }
);

(:~
 :
Retrieves all the labels with the given label role and language in the
 : matching concepts, one label for each concept.

 :
 :
Matching concepts are those which:
 :  - concept name and archive number match a given one;
 :  - component role matches a given one or is the default
 :    component role.
 :

 :
 :
The set of concepts to search in is specified as a parameter.

 :
 :
Language matching can either be exact, if no options are given,
 : or approximated, if at least one of the following options is given:

 :

 :
MatchDown: whether to match a more specific language, e.g.:
 :       "en" will match labels which language is "en" or "en-US".

 :
MatchUp: whether to match a less specific language, e.g.:
 :       "en-US" will match labels which language is "en-US" or "en".

 :
MatchAnyVariant: whether to match a different variant of the same
 :       language, e.g.: "en-US" will match labels which language is "en-US"
 :       or "en-UK".

 :

 :
 : @param $concept-names the concepts names.
 : @param $label-roles the label role.
 : @param $languages the label language.
 : @param $concepts the concepts in which the labels will be
 :                  searched.
 : @param $entities the entities in which entity labels will be searched.
 : @param $options Optional parameters to control language matching.
 :
 : @return the matching labels (one associated with each input concept, as
 : an object).
 :)
declare function labels:labels(
    $concept-names as string*,
    $label-roles as string*,
    $languages as string*,
    $concepts as object*,
    $entities as object*,
    $options as object?
  ) as object
{
  let $concepts := ($labels:standard-concepts, $concepts)
  return {|
    let $normalized-languages as string* := $languages ! labels:normalize-language($$)
    return (
      for $concept as object in $concepts
      where ($concepts:ALL_CONCEPT_NAMES, $concept.$concepts:NAME) = $concept-names
      group by $concept.$concepts:NAME
      let $concept-labels as object* :=
        for $label-role in $label-roles
        return $concept.$concepts:LABELS[][$$.Role = $label-role]
      let $available-languages as string* :=
        distinct-values($concept-labels.Language)
      let $approximate-languages as string* := labels:approximate-languages(
        $available-languages,
        $normalized-languages,
        $options
      )
      let $english-languages as string* := labels:approximate-languages(
        $available-languages,
        "en",
        $options
      )
      let $perfect-matches as object* :=
        $concept-labels[$$.Language = $normalized-languages]
      let $approximate-matches as object* :=
        $concept-labels[$$.Language = $approximate-languages]
      let $english-matches as object* :=
        $concept-labels[$$.Language = $english-languages]
      let $label as string? :=
        ($perfect-matches.Value,
         $approximate-matches.Value,
         $english-matches.Value,
         $concept-labels.Value,
         $concept.Label)[not $$ instance of null][1]
      where exists($label)
      return {
        $concept.Name : $label
      },

      for $concept as string in $concept-names
      where not (($concepts:ALL_CONCEPT_NAMES, $concepts.$concepts:NAME) = $concept)
      let $label as string* :=
          switch(true)
            case starts-with($concept, "iso4217:")
            return substring($concept, 9)
            case $concept castable as date
            return format-date(date($concept), "[MNn] [D], [Y]", "en", (), ())
            case (every $date in tokenize($concept, "/") satisfies $date castable as date)
            return "From " || string-join(
                     for $date in tokenize($concept, "/")
                     return format-date(date($date), "[MNn] [D], [Y]", "en", (), ()),
                   " to ")
            case contains($concept, " ")
            return
              let $entities-found as object* := $entities[entities:eid($$) = $concept]
              let $entity-id-no-scheme as string? := tokenize($concept, " ")[2]
              return
              switch(true)
              case exists($entities-found) and $normalized-languages = ("ja")
              return ($entities-found.Profiles.SEC.EntityRegistrantName,
                       $entities-found.Profiles.FSA.SubmitterName !
                           ($$ || " (" || $entity-id-no-scheme || ")")
                     )[1]
              case exists($entities-found)
              return ($entities-found.Profiles.SEC.CompanyName !
                          ($$ || " (" || string(integer($entity-id-no-scheme)) || ")"),
                      $entities-found.Profiles.FSA.SubmitterNameAlphabetic !
                          ($$ || " (" || $entity-id-no-scheme || ")")
                     )[1]
              default return ()
           default return ()
      where exists($label)
      return {
        $concept : $label
      }
    )
  |}
};

(:~
 :
Retrieves all the labels with the given label role and language for
 : all concepts used in the fact and matching a concept in the list of
 : concepts. Concepts used in a fact include not only those from the
 : 'xbrl:Concept' aspect, but also Members of any custom axis.

 :
 :
Matching concepts are those which:
 :  - concept name matches a given one,
 :  - archive number matches that of a given component,
 :  - component role matches that of a given component or is the default
 :    component role.
 :

 :
 :
The set of concepts to search in is specified as a parameter.

 :
 :
Language matching can either be exact, if no options are given,
 : or approximated, if at least one of the following options is given:

 :

 :
MatchDown: whether to match a more specific language, e.g.:
 :       "en" will match labels which language is "en" or "en-US".

 :
MatchUp: whether to match a less specific language, e.g.:
 :       "en-US" will match labels which language is "en-US" or "en".

 :
MatchAnyVariant: whether to match a different variant of the same
 :       language, e.g.: "en-US" will match labels which language is "en-US"
 :       or "en-UK".

 :

 :
 : @param $facts a sequence of facts.
 : @param $label-role the label role.
 : @param $language the label language.
 : @param $concepts the concepts in which the labels will be
 :                  searched (in the version-7 format).
 : @param $options optional parameters to control language matching.
 :
 : @return an object with matching concepts as keys and labels as values.
 :)
declare function labels:labels-for-facts(
    $facts as object*,
    $label-role as string,
    $language as string,
    $concepts as object*,
    $entities as object*,
    $options as object?
  ) as object?
{
    for $facts in $facts
    group by $archive := $facts."Aspects"."xbrl28:Archive"
    let $concept-names as string* :=
        distinct-values((
          values($facts.Aspects),
          keys($facts.Aspects)
    )[$$ instance of string])
    return
        {|
            labels:labels(
                    $concept-names,
                    $label-role,
                    $language,
                    $concepts,
                    $entities,
                    $options)
        |}
};

(:~
 :
Normalizes the language code. This normalized language code can then
 : be used to find the right labels in the concepts collection.

 :
 : @param $language the language identifier.
 :
 : @return the normalized language.
 :)
declare function labels:normalize-language($language as string) as string
{
  replace(lower-case($language), "_", "-")
};

declare %private function labels:approximate-languages(
    $all-languages as string*,
    $normalized-language as string,
    $options as object?
  ) as string*
{
    if(not $options.MatchDown cast as boolean? eq false)
    then $all-languages[starts-with($$, $normalized-language)]
    else (),
    if(not $options.MatchUp cast as boolean? eq false)
    then $all-languages[starts-with($normalized-language, $$)]
    else (),
    if ((not $options.MatchAnyVariant cast as boolean? eq false) and contains($normalized-language, "-"))
    then
      $all-languages[starts-with($$, substring-before($normalized-language, "-") || "-")]
    else ()
};

(:~
 :
Transforms concept labels into XBRL labelLink.

 :
 : @param $concepts the concepts to transform.
 :
 : @return the labelLink element to be put into a linkbase.
 :)
declare function labels:to-xbrl(
    $concepts as object*,
    $taxonomyName as string) as element()
{
  <link:labelLink xmlns:link="http://www.xbrl.org/2003/linkbase" xlink:type="extended" xlink:role="http://www.xbrl.org/2003/role/link">
  {
    for $concept as object in $concepts
    where not $concept.Name = $concepts:BUILT_IN_REPORT_ELEMENTS
    group by $concept.Name
    let $id as string := replace($concept.Name[1], ":", "_")
    return
      (
        <link:loc xlink:type="locator" xlink:href="{$taxonomyName||"-"||tokenize($concept.Name[1], ":")[1]}.xsd#{$id}" xlink:label="{$id}" />,
        for $label at $pos in $concept.Labels[]
        let $role as string := ($label.Role, "http://www.xbrl.org/2003/role/label")[1]
        let $lang as string := ($label.Language, "de")[1]
        group by $role, $lang
        let $value as string? := ($label.Value)[$$ instance of string][1]
        let $labelID as string := $id || "_label" || $pos[1]
        return (
            <link:label xlink:role="{$role}"
                   xlink:label="{$labelID}"
                   id="{$labelID}"
                   xml:lang="{$lang}"
                   xlink:type="resource">{$value}</link:label>,
            <link:labelArc xlink:type="arc"
                      xlink:arcrole="http://www.xbrl.org/2003/arcrole/concept-label"
                      xlink:from="{$id}"
                      xlink:to="{$labelID}" />
        )
      )
  }</link:labelLink>
};

jsoniq version "1.0";
(:
 : Copyright 2015 28msec Inc.
 :)

(:~
 :
This module provides functionality for retrieving labels.

 :
 : @author Federico Cavalieri, Ghislain Fourny
 :)
module namespace labels = "http://28.io/modules/xbrl/labels";

import module namespace concepts = "http://28.io/modules/xbrl/concepts";
import module namespace entities = "http://28.io/modules/xbrl/entities";

declare namespace xbrli = "http://www.xbrl.org/2003/instance";
declare namespace xlink = "http://www.w3.org/1999/xlink";

declare namespace ver = "http://zorba.io/options/versioning";
declare option ver:module-version "1.0";

(:~
 : A helper variable holding the default language ("en-US")
 :)
declare variable $labels:AMERICAN_ENGLISH as xs:string := "en-US";

(:~
 : The standard label role.
 :)
declare variable $labels:STANDARD_LABEL_ROLE as xs:string :=
    "http://www.xbrl.org/2003/role/label";

(:~
 : The verbose label role.
 :)
declare variable $labels:VERBOSE_LABEL_ROLE as xs:string :=
    "http://www.xbrl.org/2003/role/verboseLabel";

declare variable $labels:standard-concepts as object* :=
(
    {
      Name: "xbrl:Concept",
      Label: "Concept [Axis]",
      Kind: "Dimension",
      IsNillable: true,
      IsAbstract: true,
      PeriodType: "duration",
      SubstitutionGroup: "xbrldt:dimensionItem",
      DataType: "nonnum:domainItemType",
      BaseType: "string",
      ClosestSchemaBuiltinType: "xs:string",
      IsTextBlock: false,
      Labels: [
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "fr",
          Value: "Concept [Axe]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "de",
          Value: "Konzept [Achse]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "en-us",
          Value: "Concept [Axis]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "ja",
          Value: "項目(Concept)"
        }
      ]
    },
    {
      Name: "xbrl:Period",
      Label: "Period [Axis]",
      Kind: "Dimension",
      IsNillable: true,
      IsAbstract: true,
      PeriodType: "duration",
      SubstitutionGroup: "xbrldt:dimensionItem",
      DataType: "nonnum:domainItemType",
      BaseType: "string",
      ClosestSchemaBuiltinType: "xs:string",
      IsTextBlock: false,
      Labels: [
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "fr",
          Value: "Période [Axe]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "en-us",
          Value: "Period [Axis]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "de",
          Value: "Periode [Achse]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "ja",
          Value: "期間(Period)"
        }
      ]
    },
    {
      Name: "xbrl:Entity",
      Label: "Entity [Axis]",
      Kind: "Dimension",
      IsNillable: true,
      IsAbstract: true,
      PeriodType: "duration",
      SubstitutionGroup: "xbrldt:dimensionItem",
      DataType: "nonnum:domainItemType",
      BaseType: "string",
      ClosestSchemaBuiltinType: "xs:string",
      IsTextBlock: false,
      Labels: [
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "de",
          Value: "Entität [Achse]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "fr",
          Value: "Entité [Axe]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "en-us",
          Value: "Reporting Entity [Axis]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "ja",
          Value: "企業名(Entity)"
        }
      ]
    },
    {
      Name: "xbrl28:Archive",
      Label: "Archiv [Achse]",
      Kind: "Dimension",
      IsNillable: true,
      IsAbstract: true,
      PeriodType: "duration",
      SubstitutionGroup: "xbrldt:dimensionItem",
      DataType: "nonnum:domainItemType",
      BaseType: "string",
      ClosestSchemaBuiltinType: "xs:string",
      IsTextBlock: false,
      Labels: [
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "fr",
          Value: "Archive [Axe]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "de",
          Value: "Archiv [Achse]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "en-us",
          Value: "Archive [Axis]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "ja",
          Value: "ファイル(Archive)"
        }
      ]
    },
    {
      Name: "fsa:FiscalYear",
      Label: "Fiscal Year [Axis]",
      Kind: "Dimension",
      IsNillable: true,
      IsAbstract: true,
      PeriodType: "duration",
      SubstitutionGroup: "xbrldt:dimensionItem",
      DataType: "nonnum:domainItemType",
      BaseType: "string",
      ClosestSchemaBuiltinType: "xs:string",
      IsTextBlock: false,
      Labels: [
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "fr",
          Value: "Année fiscale [Axe]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "de",
          Value: "Steuerjahr [Achse]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "ja",
          Value: "会計年度(Fiscal Year)"
        }
      ]
    },
    {
      Name: "fsa:FiscalPeriod",
      Label: "Fiscal Period [Axis]",
      Kind: "Dimension",
      IsNillable: true,
      IsAbstract: true,
      PeriodType: "duration",
      SubstitutionGroup: "xbrldt:dimensionItem",
      DataType: "nonnum:domainItemType",
      BaseType: "string",
      ClosestSchemaBuiltinType: "xs:string",
      IsTextBlock: false,
      Labels: [
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "ja",
          Value: "会計期間(Fiscal Period)"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "en-us",
          Value: "Fiscal Period [Axis]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "fr",
          Value: "Période fiscal [Axe]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "de",
          Value: "Steuerperiode [Achse]"
        }
      ]
    },
    {
      Name: "fsa:FiscalPeriodType",
      Label: "Fiscal Period Type [Axis]",
      Kind: "Dimension",
      IsNillable: true,
      IsAbstract: true,
      PeriodType: "duration",
      SubstitutionGroup: "xbrldt:dimensionItem",
      DataType: "nonnum:domainItemType",
      BaseType: "string",
      ClosestSchemaBuiltinType: "xs:string",
      IsTextBlock: false,
      Labels: [
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "ja",
          Value: "会計期間タイプ(Fiscal Period Type)"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "en-us",
          Value: "Fiscal Period Type [Axis]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "fr",
          Value: "Type de période fiscale [Axe]"
        },
        {
          Role: "http://www.xbrl.org/2003/role/label",
          Language: "de",
          Value: "Steuerperiodeart [Achse]"
        }
      ]
    }
);

(:~
 :
Retrieves all the labels with the given label role and language in the
 : matching concepts, one label for each concept.

 :
 :
Matching concepts are those which:
 :  - concept name and archive number match a given one;
 :  - component role matches a given one or is the default
 :    component role.
 :

 :
 :
The set of concepts to search in is specified as a parameter.

 :
 :
Language matching can either be exact, if no options are given,
 : or approximated, if at least one of the following options is given:

 :

 :
MatchDown: whether to match a more specific language, e.g.:
 :       "en" will match labels which language is "en" or "en-US".

 :
MatchUp: whether to match a less specific language, e.g.:
 :       "en-US" will match labels which language is "en-US" or "en".

 :
MatchAnyVariant: whether to match a different variant of the same
 :       language, e.g.: "en-US" will match labels which language is "en-US"
 :       or "en-UK".

 :

 :
 : @param $concept-names the concepts names.
 : @param $label-roles the label role.
 : @param $languages the label language.
 : @param $concepts the concepts in which the labels will be
 :                  searched.
 : @param $entities the entities in which entity labels will be searched.
 : @param $options Optional parameters to control language matching.
 :
 : @return the matching labels (one associated with each input concept, as
 : an object).
 :)
declare function labels:labels(
    $concept-names as string*,
    $label-roles as string*,
    $languages as string*,
    $concepts as object*,
    $entities as object*,
    $options as object?
  ) as object
{
  let $concepts := ($labels:standard-concepts, $concepts)
  return {|
    let $normalized-languages as string* := $languages ! labels:normalize-language($$)
    return (
      for $concept as object in $concepts
      where ($concepts:ALL_CONCEPT_NAMES, $concept.$concepts:NAME) = $concept-names
      group by $concept.$concepts:NAME
      let $concept-labels as object* :=
        for $label-role in $label-roles
        return $concept.$concepts:LABELS[][$$.Role = $label-role]
      let $available-languages as string* :=
        distinct-values($concept-labels.Language)
      let $approximate-languages as string* := labels:approximate-languages(
        $available-languages,
        $normalized-languages,
        $options
      )
      let $english-languages as string* := labels:approximate-languages(
        $available-languages,
        "en",
        $options
      )
      let $perfect-matches as object* :=
        $concept-labels[$$.Language = $normalized-languages]
      let $approximate-matches as object* :=
        $concept-labels[$$.Language = $approximate-languages]
      let $english-matches as object* :=
        $concept-labels[$$.Language = $english-languages]
      let $label as string? :=
        ($perfect-matches.Value,
         $approximate-matches.Value,
         $english-matches.Value,
         $concept-labels.Value,
         $concept.Label)[not $$ instance of null][1]
      where exists($label)
      return {
        $concept.Name : $label
      },

      for $concept in $concept-names
      where not (($concepts:ALL_CONCEPT_NAMES, $concepts.$concepts:NAME) = $concept)
      let $label as string* :=
          switch(true)
            case starts-with($concept, "iso4217:")
            return substring($concept, 9)
            case $concept castable as date
            return format-date(date($concept), "[MNn] [D], [Y]", "en", (), ())
            case (every $date in tokenize($concept, "/") satisfies $date castable as date)
            return "From " || string-join(
                     for $date in tokenize($concept, "/")
                     return format-date(date($date), "[MNn] [D], [Y]", "en", (), ()),
                   " to ")
            case contains($concept, " ")
            return
              switch(true)
              case $concept = entities:eid($entities) and $normalized-languages = ("ja")
              return ($entities[entities:eid($$) = $concept].Profiles.SEC.EntityRegistrantName,
                       $entities[entities:eid($$) = $concept].Profiles.FSA.SubmitterName !
                           ($$ || " (" || tokenize($concept, " ")[2] || ")")
                     )[1]
              case $concept = entities:eid($entities)
              return ($entities[entities:eid($$) = $concept].Profiles.SEC.CompanyName !
                          ($$ || " (" || string(integer(tokenize($concept, " ")[2])) || ")"),
                      $entities[entities:eid($$) = $concept].Profiles.FSA.SubmitterNameAlphabetic !
                          ($$ || " (" || tokenize($concept, " ")[2] || ")")
                     )[1]
              default return ()
           default return ()
      where exists($label)
      return {
        $concept : $label
      }
    )
  |}
};

(:~
 :
Retrieves all the labels with the given label role and language for
 : all concepts used in the fact and matching a concept in the list of
 : concepts. Concepts used in a fact include not only those from the
 : 'xbrl:Concept' aspect, but also Members of any custom axis.

 :
 :
Matching concepts are those which:
 :  - concept name matches a given one,
 :  - archive number matches that of a given component,
 :  - component role matches that of a given component or is the default
 :    component role.
 :

 :
 :
The set of concepts to search in is specified as a parameter.

 :
 :
Language matching can either be exact, if no options are given,
 : or approximated, if at least one of the following options is given:

 :

 :
MatchDown: whether to match a more specific language, e.g.:
 :       "en" will match labels which language is "en" or "en-US".

 :
MatchUp: whether to match a less specific language, e.g.:
 :       "en-US" will match labels which language is "en-US" or "en".

 :
MatchAnyVariant: whether to match a different variant of the same
 :       language, e.g.: "en-US" will match labels which language is "en-US"
 :       or "en-UK".

 :

 :
 : @param $facts a sequence of facts.
 : @param $label-role the label role.
 : @param $language the label language.
 : @param $concepts the concepts in which the labels will be
 :                  searched (in the version-7 format).
 : @param $options optional parameters to control language matching.
 :
 : @return an object with matching concepts as keys and labels as values.
 :)
declare function labels:labels-for-facts(
    $facts as object*,
    $label-role as string,
    $language as string,
    $concepts as object*,
    $entities as object*,
    $options as object?
  ) as object?
{
    for $facts in $facts
    group by $archive := $facts."Aspects"."xbrl28:Archive"
    let $concept-names as string* :=
        distinct-values((
          values($facts.Aspects),
          keys($facts.Aspects)
    )[$$ instance of string])
    return
        {|
            labels:labels(
                    $concept-names,
                    $label-role,
                    $language,
                    $concepts,
                    $entities,
                    $options)
        |}
};

(:~
 :
Normalizes the language code. This normalized language code can then
 : be used to find the right labels in the concepts collection.

 :
 : @param $language the language identifier.
 :
 : @return the normalized language.
 :)
declare function labels:normalize-language($language as string) as string
{
  replace(lower-case($language), "_", "-")
};

declare %private function labels:approximate-languages(
    $all-languages as string*,
    $normalized-language as string,
    $options as object?
  ) as string*
{
    if(not $options.MatchDown cast as boolean? eq false)
    then $all-languages[starts-with($$, $normalized-language)]
    else (),
    if(not $options.MatchUp cast as boolean? eq false)
    then $all-languages[starts-with($normalized-language, $$)]
    else (),
    if ((not $options.MatchAnyVariant cast as boolean? eq false) and contains($normalized-language, "-"))
    then
      $all-languages[starts-with($$, substring-before($normalized-language, "-") || "-")]
    else ()
};

(:~
 :
Transforms concept labels into XBRL labelLink.

 :
 : @param $concepts the concepts to transform.
 :
 : @return the labelLink element to be put into a linkbase.
 :)
declare function labels:to-xbrl(
    $concepts as object*,
    $taxonomyName as string) as element()
{
  <link:labelLink xmlns:link="http://www.xbrl.org/2003/linkbase" xlink:type="extended" xlink:role="http://www.xbrl.org/2003/role/link">
  {
    for $concept as object in $concepts
    where not $concept.Name = $concepts:BUILT_IN_REPORT_ELEMENTS
    group by $concept.Name
    let $id as string := replace($concept.Name[1], ":", "_")
    return
      (
        <link:loc xlink:type="locator" xlink:href="{$taxonomyName||"-"||tokenize($concept.Name[1], ":")[1]}.xsd#{$id}" xlink:label="{$id}" />,
        for $label at $pos in $concept.Labels[]
        let $role as string := ($label.Role, "http://www.xbrl.org/2003/role/label")[1]
        let $lang as string := ($label.Language, "de")[1]
        group by $role, $lang
        let $value as string? := ($label.Value)[$$ instance of string][1]
        let $labelID as string := $id || "_label" || $pos[1]
        return (
            <link:label xlink:role="{$role}"
                   xlink:label="{$labelID}"
                   id="{$labelID}"
                   xml:lang="{$lang}"
                   xlink:type="resource">{$value}</link:label>,
            <link:labelArc xlink:type="arc"
                      xlink:arcrole="http://www.xbrl.org/2003/arcrole/concept-label"
                      xlink:from="{$id}"
                      xlink:to="{$labelID}" />
        )
      )
  }</link:labelLink>
};


:arrow_up: Migrate entities module.

:arrow_up: Migrate entities module.

jsoniq version "1.0";
(:
 : Copyright 2013 28msec Inc.
 :)

(:~
 :
This module provides functions for retrieving information about entities.
 : Entities submit archives (see archives module),
 : for example, to a reporting authority. Entities
 : are identified with an EID (Entity ID).

 :
 :
With this module, you can retrieve all entities, or a certain number of entities
 : with their EIDs, or obtain the EID of entities you already have.

 :
 :
Entities are stored in a MongoDB datasource called xbrl.

 :
 :
Each entity can be associated with a set of tags that makes it easier
 : to manage them. The e:entities#1 function
 : allows to retrieve all entities with a given tag.

 :
 : @author Charles Hoffman
 : @author Matthias Brantner
 : @author Dennis Knochenwefel
 : @author Ghislain Fourny
 :
 :)
module namespace entities = "http://28.io/modules/xbrl/entities";

import module namespace mw = "http://28.io/modules/xbrl/data-source-wrapper";

declare namespace ver = "http://zorba.io/options/versioning";
declare option ver:module-version "1.0";

(:~
 : Name of the collection the entities are stored in.
 :)
declare variable $entities:col as string := "entities";

(:~
 :
Return all entities.

 :
 : @return all entities.
 :)
declare function entities:entities() as object*
{
  mw:find($entities:col, {})
};

(:~
 :
Return the entities with the given EIDs.

 :
 : @param $entities-or-ids the ids of the entities (EIDs) or the entities themselves.
 :
 : @return the entities with the given EIDs
 :         the empty sequence if no entity was found or if the input is an
 : empty sequence.
 :)
declare function entities:entities($entities-or-ids as item*) as object*
{
  let $ids as string* :=
    for $s in $entities-or-ids
    where $s instance of string
    return entities:eid($s)
  let $entities as object* :=
    for $s in $entities-or-ids
    where $s instance of object
    return $s
  return
    (
      $entities,
      if (exists($ids))
      then mw:find($entities:col, {
        "$or" : [
          { "_id" : [ $ids ] },
          { "EIDs" : [ $ids ] }
        ]
      })[1]
      else ()
    )
};

(:~
 :
 :
Converts the input to a normalized entity identifier (EID). The input
 : can be either an EID, or an entity object which contains an _id.

 :
 : @param $entity-or-id a sequence of entity objects or EIDs.
 :
 : @error entities:INVALID_PARAMETER if the EID or entity is not valid.
 :
 : @return the normalized EIDs.
 :)
declare function entities:eid($entities-or-ids as item*) as atomic*
{
  distinct-values(
    for $entity-or-id in $entities-or-ids
    return
    typeswitch ($entity-or-id)
    case $entity as object return
      let $id := ($entity._id[empty($entity.EIDs)], $entity.EIDs[])
      return if(exists($id))
             then $id
             else error(QName("entities:INVALID_PARAMETER"),
                        "Invalid entity provided (no _id or EIDs field)")
    case $id as atomic return $id
    default return error(
        QName("entities:INVALID_PARAMETER"),
        "Invalid entity or id (must be an object or an atomic): "
        || serialize($entity-or-id))
  )
};

jsoniq version "1.0";
(:
 : Copyright 2013 28msec Inc.
 :)

(:~
 :
This module provides functions for retrieving information about entities.
 : Entities submit archives (see archives module),
 : for example, to a reporting authority. Entities
 : are identified with an EID (Entity ID).

 :
 :
With this module, you can retrieve all entities, or a certain number of entities
 : with their EIDs, or obtain the EID of entities you already have.

 :
 :
Entities are stored in a MongoDB datasource called xbrl.

 :
 :
Each entity can be associated with a set of tags that makes it easier
 : to manage them. The e:entities#1 function
 : allows to retrieve all entities with a given tag.

 :
 : @author Charles Hoffman
 : @author Matthias Brantner
 : @author Dennis Knochenwefel
 : @author Ghislain Fourny
 :
 :)
module namespace entities = "http://28.io/modules/xbrl/entities";

import module namespace mw = "http://28.io/modules/xbrl/mongo-wrapper";

declare namespace ver = "http://zorba.io/options/versioning";
declare option ver:module-version "1.0";

(:~
 : Name of the collection the entities are stored in.
 :)
declare variable $entities:col as string := "entities";

(:~
 :
Return all entities.

 :
 : @return all entities.
 :)
declare function entities:entities() as object*
{
  mw:find($entities:col, {})
};

(:~
 :
Return the entities with the given EIDs.

 :
 : @param $entities-or-ids the ids of the entities (EIDs) or the entities themselves.
 :
 : @return the entities with the given EIDs
 :         the empty sequence if no entity was found or if the input is an
 : empty sequence.
 :)
declare function entities:entities($entities-or-ids as item*) as object*
{
  let $ids as string* :=
    for $s in $entities-or-ids
    where $s instance of string
    return entities:eid($s)
  let $entities as object* :=
    for $s in $entities-or-ids
    where $s instance of object
    return $s
  return
    (
      $entities,
      if (exists($ids))
      then mw:find($entities:col, {
        "$or" : [
          { "_id" : [ $ids ] },
          { "EIDs" : [ $ids ] }
        ]
      })[1]
      else ()
    )
};

(:~
 :
 :
Converts the input to a normalized entity identifier (EID). The input
 : can be either an EID, or an entity object which contains an _id.

 :
 : @param $entity-or-id a sequence of entity objects or EIDs.
 :
 : @error entities:INVALID_PARAMETER if the EID or entity is not valid.
 :
 : @return the normalized EIDs.
 :)
declare function entities:eid($entities-or-ids as item*) as atomic*
{
  distinct-values(
    for $entity-or-id in $entities-or-ids
    return
    typeswitch ($entity-or-id)
    case $entity as object return
      let $id := ($entity._id[empty($entity.EIDs)], $entity.EIDs[])
      return if(exists($id))
             then $id
             else error(QName("entities:INVALID_PARAMETER"),
                        "Invalid entity provided (no _id or EIDs field)")
    case $id as atomic return $id
    default return error(
        QName("entities:INVALID_PARAMETER"),
        "Invalid entity or id (must be an object or an atomic): "
        || serialize($entity-or-id))
  )
};


currently not able to use object function

declare namespace an = "http://www.zorba-xquery.com/annotations";

declare default function namespace "foo.com";

declare variable $input:=
  for $i in 1 to 1000
  return ({"a":3, "b" : "foo"}, {"a": { "d" : 4}, "c":[1,2,3]});

declare %an:sequential function collapse-general($x)
{
   variable $val := [], $obj := [], $arr := [];

   $x ! (typeswitch (.)
         case object() return  { append json . into $obj; }
         case array() return { append json . into $arr; }
         default return { append json . into $val; });

   if (size($val) eq 0)
   then ()
   else ["_VAL", members($val)],

   if (size($obj) eq 0)
   then ()
   else ["_OBJ", collapse-objects(members($obj))],

   if (size($arr) eq 0)
   then ()
   else  ["_ARR", collapse-general(members($arr) ! members(.)) ]
};

declare %an:sequential function collapse-objects($x as object()*)
{
  {| for $y in distinct-values($x ! (keys(.)))
         let $z := $x($y)
         return {$y : collapse-general($z)} |}
};

collapse-objects($input),
"
"

declare namespace an = "http://www.zorba-xquery.com/annotations";

declare default function namespace "foo.com";

declare variable $input:=
  for $i in 1 to 1000
  return ({"a":3, "b" : "foo"}, {"a": { "d" : 4}, "c":[1,2,3]});

declare %an:sequential function collapse-general($x)
{
   variable $val := [], $obj := [], $arr := [];

   $x ! (typeswitch (.)
         case object() return  { append json . into $obj; }
         case array() return { append json . into $arr; }
         default return { append json . into $val; });

   if (size($val) eq 0)
   then ()
   else ["_VAL", members($val)],

   if (size($obj) eq 0)
   then ()
   else ["_OBJ", collapse-objects(members($obj))],

   if (size($arr) eq 0)
   then ()
   else  ["_ARR", collapse-general(members($arr) ! members(.)) ]
};

declare %an:sequential function collapse-objects($x as object()*)
{
  object(for $y in distinct-values($x ! (keys(.)))
         let $z := $x($y)
         return {$y : collapse-general($z)})
};

collapse-objects($input),
"
"