Getting Started with Query XSD Analysis

Getting Started

What is Query XSD Analysis?

Query XSD Analysis is a set of features that provides the ability to analyse XML Schemas (XSD) files using common query languages. Typical analysis tasks include checking for conformance to naming conventions, use of anonymous types, elements and attributes, namespaces, spell checking, organizational patterns and detection and analysis of class hierarchies.

Generated reports are typically used as part of an ongoing quality and compliance programs, and are usually integrated with an automated build processes. A report item pinpoints the exact line and column position in the XSD file related to analysis item; integrating specific messages providing details about the test condition further helps with the usability of the analysis result. The intent is to reduce the learning curve associated with developing XSD models within large organizations subject to complex conformance profiles.

Our team will release in the near future conformance packs, which consist of predefined rule bundles that capture best industry practices, as well as more specific design patterns to help with customizations of industry standard XSDs.

To analyze XSDs, the entire set of XSD files must be valid.

We currently support SQL only.

Relational Metamodel

The relational metamodel used to construct the queries is available in the Model View tab of the QXSD designer. It is similar to the .NET XML Schema API.

QXSD Metamodel
QXSD Metamodel
(Click to Enlarge)

 The object browser on the right can be used to quickly find entities.

Examples

For illustration we're using the purchase order sample XSD published by W3C with XSD 1.0 Primer (a downloadable file is available here; we've posted a quick overview here). First step is to create an XSR XML Schema Collection object, and attach the po.xsd file to it. From the context menu on the Version object, invoke the Query XSD Analysis command.

Query XSD Analysis starting configuration
Query XSD Analysis starting configuration
(Click to Enlarge)

 Authoring Styles

 There are four major authoring styles:

  • Salami Slice
  • Venetian Blind
  • Russian Doll
  • The Garden of Eden

For each of the authoring styles, we provide a list of rules to illustrate analysis examples. The rule sets are not meant to be exhaustive.

Salami Slice

Locally defined elements are not allowed.

The query below finds all locally defined elements; in effect, it produces the list of exceptions to the rule.

Select XSElement.LocalName,
XSObject.LineNumber,
XSObject.LinePosition,
XSObject.SourceUri
From XSElement
Inner Join XSObject On XSElement.RowId = XSObject.RowId
Where XSElement.RefLocalName Is Null And XSObject.IsGlobal = 0

Query to find all local elements
Query to find all local elements
(Click to Enlarge)

Results:

Local Name Line Number Line Position Source Uri
street 28 5 file:///.../QTAssistant/po.xsd
productName 41 8 file:///.../QTAssistant/po.xsd
state 30 5 file:///.../QTAssistant/po.xsd
city 29 5 file:///.../QTAssistant/po.xsd
shipTo 17 5 file:///.../QTAssistant/po.xsd
zip 31 5 file:///.../QTAssistant/po.xsd
item 38 5 file:///.../QTAssistant/po.xsd
shipDate 51 8 file:///.../QTAssistant/po.xsd
quantity 42 8 file:///.../QTAssistant/po.xsd
USPrice 49 8 file:///.../QTAssistant/po.xsd
items 20 5 file:///.../QTAssistant/po.xsd
billTo 18 5 file:///.../QTAssistant/po.xsd
name 27 5 file:///.../QTAssistant/po.xsd

User defined global types are not allowed.

The query below finds all the global types; in effect, it produces the list of exceptions to the rule.

Select XSType.LocalName,
XSObject.LineNumber,
XSObject.LinePosition,
XSObject.SourceUri
From XSType
Inner Join XSObject On XSType.RowId = XSObject.RowId
Where XSObject.IsGlobal = 1

 

Query to find all global types
Query to find all global types
(Click to Enlarge)

 

Results

Local Name Line Number Line Position Source Uri
PurchaseOrderType 15 3 file:///.../QTAssistant/po.xsd
USAddress 25 3 file:///.../QTAssistant/po.xsd
SKU 60 3 file:///.../QTAssistant/po.xsd
Items 36 3 file:///.../QTAssistant/po.xsd

 

Venetian Blind

Locally defined types are not allowed.

The query below finds all the local types; in effect, it produces the list of exceptions to the rule.

Select XSObject.LineNumber,
XSObject.LinePosition,
XSObject.SourceUri
From XSType
Inner Join XSObject On XSType.RowId = XSObject.RowId
Where XSObject.IsGlobal = 0

 

References to globally defined elements are not allowed.

This rule implies that all global elements are "there" to define XML root elements. The query below finds all particle elements that reference a global definition, thus it produces the list of exceptions to the rule.

Select XSElement.LocalName,
  XSObject.LineNumber,
  XSObject.LinePosition,
  XSObject.SourceUri
From XSObject
  Inner Join XSElement On XSElement.RowId = XSObject.RowId
Where XSElement.RefLocalName Is Not Null

 

Results:

Local Name Line Number Line Position Source Uri
comment 50 8 file:///.../QTAssistant/po.xsd
comment 19 5 file:///.../QTAssistant/po.xsd
 

Russian Doll

User defined global types are not allowed.

See the same rule under Salami Slice.

References to globally defined elements are not allowed.

See the same rule under Venetian Blind.

 

The Garden Of Eden

Locally defined elements are not allowed.

See the same rule under Salami Slice.

Locally defined types are not allowed.

See the same rule under Venetian Blind.

 

Spell Check

The ability to spell check relies on buit in dictionaries. The user has the ability to override the built in dictionaries, and add a custom one to allow inclusion of specific terms in order to manage false hits.

A more complex SQL script, such as the one used in this example, requires the use of the SQL tab.

Query XSD Analysis SQL tab with spell checking script
Query XSD Analysis SQL tab with spell checking script
(Click to Enlarge)

 

--// Spellcheck
DECLARE @dictkey NVARCHAR
DECLARE @optionsspelling INT

set @optionsspelling = SpellCheckOptionsMask(0, 0, 0, 0, 0, 0)

set @dictkey = SpellCheckAddDictionary('custom', 'PATH TO CUSTOM DICT', '', '', NULL, @optionsspelling)
set @dictkey = SpellCheckAddDictionary(NULL, NULL, NULL, NULL, NULL, @optionsspelling)

--// Splits camel case names for elements and types.
SELECT Names.LocalName, RegexSplitSpellCheckValid(
 RegexReplace(
  RegexReplace(
     --// Use it to clean things that shouldn't go in
     --// the custom dictionary such as prefixes, suffixes, etc.
     RegexReplace(
        Names.LocalName,
       '(-Suffix$|^Prefix)',
       '',
       NULL
     ),
     '(\P{Ll})(\P{Ll}\p{Ll})',
     '$1 $2',
     NULL
  ),
  '(\p{Ll})(\P{Ll})',
  '$1 $2',
  NULL
 ), ' ', NULL, NULL, @dictkey), XSObject.LineNumber, XSObject.LinePosition, XSObject.SourceUri
FROM
(SELECT XSType.LocalName, XSType.RowId FROM XSType WHERE XSType.LocalName IS NOT NULL
UNION
SELECT XSElement.LocalName, XSElement.RowId FROM XSElement WHERE XSElement.LocalName IS NOT NULL
) AS Names
INNER JOIN XSObject on Names.RowId = XSObject.RowId

 

Results:

The result set captures in Column1 the offending component and, if applicable, suggestions.

Local Name Column1 Line Number Line Position Source Uri
billTo   18 5 file:///.../QTAssistant/po.xsd
city   29 5 file:///.../QTAssistant/po.xsd
comment   13 3 file:///.../QTAssistant/po.xsd
comment   19 5 file:///.../QTAssistant/po.xsd
comment   50 8 file:///.../QTAssistant/po.xsd
item   38 5 file:///.../QTAssistant/po.xsd
items   20 5 file:///.../QTAssistant/po.xsd
Items   36 3 file:///.../QTAssistant/po.xsd
name   27 5 file:///.../QTAssistant/po.xsd
productName   41 8 file:///.../QTAssistant/po.xsd
purchaseOrder   11 3 file:///.../QTAssistant/po.xsd
PurchaseOrderType   15 3 file:///.../QTAssistant/po.xsd
quantity   42 8 file:///.../QTAssistant/po.xsd
shipDate   51 8 file:///.../QTAssistant/po.xsd
shipTo   17 5 file:///.../QTAssistant/po.xsd
SKU SKU - SK SKUA SKA SKI SKY 60 3 file:///.../QTAssistant/po.xsd
state   30 5 file:///.../QTAssistant/po.xsd
street   28 5 file:///.../QTAssistant/po.xsd
USAddress   25 3 file:///.../QTAssistant/po.xsd
USPrice   49 8 file:///.../QTAssistant/po.xsd
zip   31 5 file:///.../QTAssistant/po.xsd

By adding SKU to the custom dictionary, the offending line will clear out.