PMDL Example
The following is an example of the PMDL DTD file used by Commerce.
This is an example of the DTD file that defines the promotion attributes:
<!--
This DTD defines the circumstances under which a pricing model should be applied
Categories of expression elements:
o iterators = next, up-to-and-including, every, iterator
o operators = and, or, not, operator
o operations = anded-union
o comparators = starts-with, ends-with, contains, greater-than, less-than, equals, comparator
o quantifiers = at-least, at-most, exactly, all, quantifier
o value-names = value, constant, null
o array-names = array, value
-->
<!ENTITY % iterators "next | up-to-and-including | every | iterator">
<!ENTITY % group-iterators "every-group | up-to-and-including-group | group-iterator">
<!ENTITY % operators "and | or | not | operator">
<!ENTITY % operations "union | anded-union">
<!ENTITY % comparators "starts-with | ends-with | contains | equals | not-equals | less-than | less-than-or-equals |
greater-than | greater-than-or-equals | includes | includes-any | includes-all | isoneof | isnotoneof | comparator">
<!ENTITY % quantifiers "exactly | at-least | at-most | all | quantifier">
<!ENTITY % value-types "value | constant | null">
<!ENTITY % array-types "value | constant | array">
<!-- Root element of the pricing-model. -->
<!ELEMENT pricing-model (qualifier, (target?|offer))>
<!ELEMENT offer (attribute*, discount-structure+)>
<!ATTLIST offer
filter-collection-name CDATA #IMPLIED
quantity-property-name CDATA "quantity">
<!ELEMENT qualifier (attribute*, ((%quantifiers;) | (%operators;) | (%operations;) | (%comparators;) | (%iterators;))?) >
<!ELEMENT target (attribute*, ((%operations;) | (%iterators;) | (%group-iterators;))?) >
<!ELEMENT discount-structure (attribute*, discount-detail*, target?)>
<!ATTLIST discount-structure
calculator-type CDATA #REQUIRED
discount-type CDATA #REQUIRED
adjuster CDATA #IMPLIED
process-zero-targets CDATA "false">
<!ELEMENT discount-detail (attribute*)>
<!ATTLIST discount-detail
name CDATA #IMPLIED>
<!-- generic name/value pair used to add custom attributes and values to many elements -->
<!ELEMENT attribute EMPTY>
<!ATTLIST attribute
name CDATA #REQUIRED
value CDATA #REQUIRED>
<!-- used by iterators and quantifiers -->
<!ELEMENT element-name (#PCDATA)>
<!-- used to fully qualify a property within the environment of objects. Use dot-notation: item.sku.tracks.songTitle
or in the case of attributes just a value -->
<!ELEMENT value (#PCDATA)>
<!-- used in quantifiers and iterators to specify over which collection the element is iterating -->
<!ELEMENT collection-name (#PCDATA)>
<!-- specifies the property which is the 'quantity' of an iterator or quantifier element -->
<!ELEMENT element-quantity-property (#PCDATA)>
<!ELEMENT aggregator (attribute*)>
<!ATTLIST aggregator
name CDATA #REQUIRED
operation CDATA #REQUIRED>
<!--
Iterators
Evaluate expression elements
Built-in iterators:
o next: evaluate next n expression elements
o up-to-and-including: evaluate up to n expression elements (inclusive)
o every: evaluate all expression elements
-->
<!-- returns up to and including <number> items. It does this process exactly once the sort is performed before the items are selected -->
<!ELEMENT up-to-and-including (
attribute*,
collection-name,
element-name,
(element-quantity-property | aggregator)?,
(%comparators; | %operators; | %quantifiers;)?
)>
<!ATTLIST up-to-and-including
number CDATA #REQUIRED
sort-by CDATA #REQUIRED
sort-order CDATA #REQUIRED>
<!-- consumes every item that matches its rule. -->
<!ELEMENT every (
attribute*,
collection-name,
element-name,
(%comparators; | %operators; | %quantifiers;)?
)>
<!ATTLIST every
sort-by CDATA #IMPLIED
sort-order CDATA #IMPLIED>
<!-- consumes the next N things that match its rule. If it doesn't find N things, it -->
<!-- fails. the sort is performed before the items are selected -->
<!ELEMENT next (
attribute*,
collection-name,
element-name,
(element-quantity-property | aggregator)?,
(%comparators; | %operators; | %quantifiers;)?
)>
<!ATTLIST next
number CDATA #REQUIRED
sort-by CDATA #REQUIRED
sort-order CDATA #REQUIRED>
<!-- custom iterator can be used for extending the set of built-ins -->
<!ELEMENT iterator (
attribute*,
collection-name,
element-name,
(element-quantity-property | aggregator)?,
(%comparators; | %operators; | %quantifiers;)?
)>
<!ATTLIST iterator
name CDATA #REQUIRED
number CDATA #IMPLIED
sort-by CDATA #REQUIRED
sort-order CDATA #REQUIRED>
<!--
Group Iterators
Evaluate expression elements
Built-in iterators:
o every-group: evaluate all expression elements
o up-to-and-including-group: evaluate up to n expression elements (inclusive)
-->
<!-- consumes every group returned by the sub-expression until no more are found -->
<!ELEMENT every-group (
attribute*,
(%operations;)
)>
<!-- consumes the next N group groups returned by the sub-expression -->
<!ELEMENT up-to-and-including-group (
attribute*,
(%operations;)
)>
<!ATTLIST up-to-and-including-group
number CDATA #REQUIRED>
<!-- custom group iterator can be used for extending the set of built-ins -->
<!ELEMENT group-iterator (
attribute*,
(%operations;)
)>
<!ATTLIST group-iterator
name CDATA #REQUIRED
number CDATA #IMPLIED>
<!--
Quantifiers
Evaluate if a certain quantity of expression elements evaluate to true.
Built-in quantifiers:
o exactly: evaluates true if exactly n expression elements evaluate to true
o at-least: evaluates true if at least n expression elements evaluate to true
o at-most: evaluates true if at most n expression elements evaluate to true
o all: evaluates true if all expression elements evaluate to true
-->
<!ELEMENT exactly (
attribute*,
collection-name,
element-name,
(element-quantity-property | aggregator)?,
(%comparators; | %operators; | %quantifiers;)?
)>
<!ATTLIST exactly
number CDATA #REQUIRED>
<!ELEMENT at-least (
attribute*,
collection-name,
element-name,
(element-quantity-property | aggregator)?,
(%comparators; | %operators; | %quantifiers;)?
)>
<!ATTLIST at-least
number CDATA #REQUIRED>
<!ELEMENT at-most (
attribute*,
collection-name,
element-name,
(element-quantity-property | aggregator)?,
(%comparators; | %operators; | %quantifiers;)?
)>
<!ATTLIST at-most
number CDATA #REQUIRED>
<!ELEMENT all (
attribute*,
collection-name,
element-name,
(%comparators; | %operators; | %quantifiers;)?
)>
<!-- custom quantifier can be used for extending the set of built-ins -->
<!ELEMENT quantifier (
attribute*,
collection-name,
element-name,
(element-quantity-property | aggregator)?,
(%comparators; | %operators; | %quantifiers;)?
)>
<!ATTLIST quantifier
name CDATA #REQUIRED
number CDATA #IMPLIED>
<!--
Operators
Perform boolean logic operations on expression elements
Built-in operators:
o and: conjunction operator; evaluates true if both expression elements evaluate to true
o or: disjunction operator; evaluates true if either or both expression elements evaluate to true
o not: complement operator; negates the value of the expression element
-->
<!ELEMENT and (
attribute*,
(%comparators; | %operators; | %quantifiers;),
(%comparators; | %operators; | %quantifiers;)*
)>
<!ELEMENT or (
attribute*,
(%comparators; | %operators; | %quantifiers;),
(%comparators; | %operators; | %quantifiers;)*
)>
<!ELEMENT not (
attribute*,
(%comparators; | %operators; | %quantifiers;)
)>
<!-- custom operator can be used for extending the set of built-ins -->
<!ELEMENT operator (
attribute*,
(%comparators; | %operators; | %quantifiers;)+
)>
<!ATTLIST operator
name CDATA #REQUIRED>
<!--
Operations
Perform mathematical operations on expression elements
Built-in operators:
o union: a collection of items that are returned from each expression
-->
<!ELEMENT union (
attribute*,
(%iterators;),
(%iterators;)*
)>
<!-- anded-union: a collection of items that are returned from each expression if all iterators match -->
<!ELEMENT anded-union (
attribute*,
(%iterators;),
(%iterators;)*
)>
<!--
Comparators
Compare values and/or array with each other
Built-in comparators:
o starts-with: evaluates true if a value starts with another value
o ends-with: evaluates true if a value ends with another value
o contains: evaluates true if a value contains another value
o equals: evaluates true if a value == another value
o not-equals: evaluates true if a value != another value
o less-than: evaluates true if a value is < another value
o less-than-or-equals: evaluates true if a value <= another value
o greater-than: evaluates true if a value > another value
o greater-than-or-equals: evaluates true if a value >= another value
o includes: evaluates true if an array/value includes a value
o includes-any: evaluates true if an array/value includes any value in another array/value
o includes-all: evaluates true if an array/value includes all values in another array/value
o isoneof: evaluates true if a value is a member of an array/value
o isnotoneof: evaluates true if a value is not a member of an array/value
-->
<!ELEMENT starts-with
( attribute*, (%value-types;), (%value-types;) )>
<!ELEMENT ends-with
( attribute*, (%value-types;), (%value-types;) )>
<!ELEMENT contains
( attribute*, (%value-types;), (%value-types;) )>
<!ELEMENT equals
( attribute*, (%value-types;), (%value-types;) )>
<!ELEMENT not-equals
( attribute*, (%value-types;), (%value-types;) )>
<!ELEMENT less-than
( attribute*, (%value-types;), (%value-types;) )>
<!ELEMENT less-than-or-equals
( attribute*, (%value-types;), (%value-types;) )>
<!ELEMENT greater-than
( attribute*, (%value-types;), (%value-types;) )>
<!ELEMENT greater-than-or-equals
( attribute*, (%value-types;), (%value-types;) )>
<!ELEMENT isoneof
( attribute*, (%value-types;), (%array-types;) )>
<!ELEMENT isnotoneof
( attribute*, (%value-types;), (%array-types;) )>
<!ELEMENT includes
( attribute*, (%array-types;), (%value-types;) )>
<!ELEMENT includes-any
( attribute*, (%array-types;), (%array-types;) )>
<!ELEMENT includes-all
( attribute*, (%array-types;), (%array-types;) )>
<!-- custom comparator can be used for extending the set of built-ins -->
<!ELEMENT comparator ( attribute*, (%value-types; | %array-types;)+ )>
<!ATTLIST comparator
name CDATA #REQUIRED>
<!--
Value
Represents data (or empty)
o value: parsed character data
o constant: a data-type/string-value pair
o null: an empty value
-->
<!ELEMENT constant (data-type, string-value+)>
<!ELEMENT array (%value-types;)+>
<!ELEMENT null EMPTY>
<!ELEMENT data-type (#PCDATA)>
<!ELEMENT string-value (#PCDATA)>