The current design of the XML in CVRF defines a "branch", where a branch contains either other branches or full products. XML example:
<Branch Name="Cisco" Type="Vendor">
<Branch Name="IOS" Type="Product Name">
<Branch Name="12.2SE" Type="Product Version">
<Branch Name="12.2(55)SE" Type="Service Pack">
<FullProductName ProductID="CVRFPID-103763">Cisco IOS 12.2SE 12.2(55)SE</FullProductName>
The nested structure hides the underlying goal - associating values of well-known properties with a product. In spite of the XML nesting structure, only a subset of the Product Branch Type Model characteristics really are hierarchical (vendor, product family, product name). However, other properties such as "architecture", "specification", "language", ", "host name" are all roughly orthogonal concerns.
The structure of the CVRF XML, and the structure currently recreated in the JSON schema does not distinguish amongst the different nature of these characteristics, and favors inheritance, which makes it awkward for some uses. If we think of this instead as a table listing all the products, each product would be a row, and each column would be a property label (or a key referencing a property value in some other table).
I used the relational database analogy for a reason. It strikes me that this structure is trying to define a relational search database (for example: "which products with version > 15 on host foo are affected?") by structuring the information so that property values are inherited. Rather than inheritance, aggregation probably makes more sense.
Suggestion:
Instead of having a hierarchical tree listing products, have a simple list. Without any further changes, this would greatly expand the size of the instance documents. To avoid that, add one additional mechanism - "shared" properties. In concrete terms, an example using the data from the snippet of XML above:
{
"product_information": {
"shared_properties": {
"shared12.2SE": {
"vendor": "Cisco",
"product_name": "IOS",
"version": "12.2SE"
}
"products": [
{
"product_id": "CVRFPID-103763",
"full_name": "Cisco IOS 12.2SE 12.2(55)SE",
"service_pack": "12.2(55)SE",
"inherit" : "shared12.2SE"
},
...
]
}
}
Differences to highlight:
- product_tree becomes product_information (welcome to suggestions for better names!)
- shared_properties defines a map between an arbitrary label, and a set of properties. The label can be referenced from the "inherit" property of a "products[]" entry. In this case, I used "shared12.2SE" as an example, but it could be any meaningful or random string.
- products[] is now a flat array listing all products relevant to the document
- properties such as "service_pack" or "architecture" can be listed on individual entries, as needed.
- properties that wish to be shared with other product listings can be referenced via the "inherit" property. The value of the "inherit" property is the key name for an entry under "shared_properties". In this example, "shared12.2SE" is the only shared property.
Not shown here in the example, but probably makes sense, is to allow shared properties inherit from other shared properties.
Other reasons for an alternate approach (even if not exactly the one mentioned above:
- if vendors wish to define additional attributes with which to tag instances of products, the proper way to extend the model to incorporate those properties is now fairly obvious - they can either add those properties to the individual entries, or add them to an appropriate shared properties entry.
- The existing structure relies on a "type" field of an XML entry. In the JSON world, it makes more sense to assign new "types" as properties.
Thoughts, comments?
Eric.