Resources
When the XML encoding rules (XER or E-XER) are used, ASN.1 provides a set of encoding instructions to control the XML format. For example, to make the "currency" field to be an XML attribute, you can use this code:
UnitPrice ::= SEQUENCE {
unitPrice REAL,
currency [XER:ATTRIBUTE] VisibleString
}
ASN.1 has the ability to restrict the value of a component of a type definition to items from a "dictionary" (a reference table). It can also enforce relationships between items in such a dictionary.
For example, let's say that we have a list of products, each of them having a product code and a particular price. We would like to make sure that a message using this product code contains the correct description and price. In order to do this, we must first define a table containing "valid" kinds of products (product catalog), then define our products referencing this catalog. We use the CLASS keyword to define a reference table. In ASN.1 lingo, we will create an Information Object Class (we'll call it PRODUCT) and populate an Information Object Set 'll call it ProductCatalog):
PRODUCT ::= CLASS {
&code INTEGER (1..99999) UNIQUE,
&description VisibleString (SIZE (1..100)),
&price REAL
} WITH SYNTAX { CODE &code , DESCRIPTION &description , PRICE &price}
ProductCatalog PRODUCT ::= {
{CODE 101, DESCRIPTION "iPhone v4", PRICE 250.00} |
{CODE 102, DESCRIPTION "Android Galaxy", PRICE 250.00} |
{CODE 103, DESCRIPTION "Win7 Nokia", PRICE 150.00}
}
Now, we redefine Item from the MyShopPurchaseOrders example to refer to ProductCatalogtable.
Item ::= SEQUENCE {
itemCode PRODUCT.&code ({ProductCatalog}),
itemDescription PRODUCT.&description ({ProductCatalog}{@itemCode}),
quantity INTEGER (1..1000),
unitPrice PRODUCT.&price ({ProductCatalog}{@itemCode}),
itemTotal REAL,
isTaxable BOOLEAN
}
With these changes, if the CODE, DESCRIPTION and PRICE do not match an entry from ProductCatalog, a good ASN.1 tool should issue an error message.
ASN.1 has the ability to allow one component to determine the ASN.1 type that another component will carry. The mechanism for this is called the open type. Let's say that we want to extend the FEATURE to contain additional information about an item.
PRODUCT ::= CLASS {
&code INTEGER (1..99999) UNIQUE,
&description VisibleString (SIZE (1..100)),
&price REAL,
--OpenType-- &Feature
} WITH SYNTAX { CODE &code , DESCRIPTION &description , PRICE &price , FEATURE &Feature }
ProductCatalog PRODUCT ::= {
{CODE 101, DESCRIPTION "iPhone", PRICE 250.00, FEATURE Generation } |
{CODE 102, DESCRIPTION "Android Galaxy", PRICE 250.00, FEATURE Generation } |
{CODE 103, DESCRIPTION "Win7 Nokia", PRICE 150.00, FEATURE Generation } |
{CODE 104, DESCRIPTION "Bookshelf", PRICE 100.00, FEATURE Weight} |
{CODE 105, DESCRIPTION "Glass Egg", PRICE 2000.00, FEATURE NULL}
}
The ASN.1 types mentioned in FEATURE need to be defined.
Generation ::= ENUMERATED {two-G, three-G, four-G}
Weight ::= INTEGER
We then add the open type component called feature to carry the additional information corresponding to the item chosen.
Item ::= SEQUENCE {
itemCode PRODUCT.&code ({ProductCatalog }),
itemDescription PRODUCT.&description({ProductCatalog}{@itemCode}),
feature PRODUCT.&Feature ({ProductCatalog}{@itemCode}),
quantity INTEGER (1..1000),
unitPrice PRODUCT.&price ({ProductCatalog}{@itemCode}),
itemTotal REAL,
isTaxable BOOLEAN
}
Note that feature must carry the information specified in the table for a given code. So if itemCode is 104, "feature" must contain a Weight.
ASN.1 contains a mechanism for allowing multiple versions of a message to be exchanged without requiring all parties to be using the same version of the message. By including the ASN.1 extension mark in appropriate locations in a message, a protocol designer can ensure that releasing new versions of the protocol will not be disruptive to existing implementations. For example:
CustomerInfo ::= SEQUENCE {
companyName VisibleString (SIZE (3..50)),
billingAddress Address,
contactPhoneNumber NumericString (SIZE (7..12)),
...
}
We add the "..." to indicate that a new version may contain additional components, such as:
CustomerInfo ::= SEQUENCE {
companyName VisibleString (SIZE (3..50)),
billingAddress Address,
contactPhoneNumber NumericString (SIZE (7..12)),
...,
shippingAddress Address
}
Someone using the first version can communicate with someone using the second version since the extension marker alerts both sides of possible new or missing components. Decoders are required to accept without error additional unknown components (such as shippingAddress), as well as accepting messages in which the additional components are missing (such as when version 2 receives a message from version 1).
Note that when version 3 comes, communication with a version 1 system or with a version 2 system is still fine:
CustomerInfo ::= SEQUENCE {
companyName VisibleString (SIZE (3..50)),
billingAddress Address,
contactPhoneNumber NumericString (SIZE (7..12)),
...,
shippingAddress Address,
additionalInfo VisibleString (SIZE (1..128))
}
The following ASN.1 types can be extended: ENUMERATED, SEQUENCE, SET, CHOICE. Information Object Sets are also extensible.
All types can have extensible constraints, but only constraints on the following types are PER-visible (meaning that the PER encodings are affected by the constraint):
All assignments that define reference names (types, values, value sets, information object classes, information objects, and information object sets) can be parameterized. Parameterized types can take multiple parameters. Also, parameters can be nested.
In the following example we have two dummy parameters - normal-priority and Parameter:
Invoke-message {INTEGER:normal-priority, Parameter} ::= SEQUENCE {
component1 INTEGER DEFAULT normal-priority,
component2 Parameter }
Now we define our messages as a choice of two possibilities that differ only in the default priority and the type that is to be used:
Messages ::= CHOICE {
first Invoke-message { low-priority, Type1 },
second Invoke-message { high-priority, Type2 },
... }
Messages ::= CHOICE { -- This is what the above expands to
first SEQUENCE {
component1 INTEGER DEFAULT low-priority,
component2 Type1 },
second SEQUENCE {
component1 INTEGER DEFAULT high-priority,
component2 Type2 },
... }