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)>