The only types where this doesn't make sense is the "untyped" types xs: A function can be defined to perform this typed-value fabrication operation:. Apply the type to the item, to obtain a typed value or an error. With the XQuery 3. Note that this might be an anonymous type just as well as a named type, unlike the type identification features that are part of standard XQuery. Combined with some of the introspection functions, we can get even more powerful and flexible effects.
The function run-plugin can guarantee that a plugin function executed for some particular piece of the framework has the expected type, without having to know a priori what that type is. For true meta-programming, being able to access some of the details of the type components is important. Schema components are complex and have many interconnections and properties. Attempting to provide a clean API to access all these properties is beyond the scope of this paper.
We will content ourselves with defining a few basic accessors. Component accessors work analogously to accessors for nodes in the data model: As with the linkage functions, these functions have a zero-argument form that applies to the context item. This will make chaining them together a little more usable. Return annotations on the component as a sequence of xs: Getting at schema annotations from instances has many applications.
For example, schema annotations can be used to define business rules, widget bindings for generic UI generation, associating help text with input components, defining special indexing for certain content, defining XML mapping rules, and so on. One key difference between XML types and classes in an object-oriented programming language is that classes have methods as well as data. Combining function items with annotation accessors can bring methods to XML types as well, in a way.
Accessing facet information is important for working with simple types. The accessors already defined apply to facet component values as well. Type test matching any facet value whose name matches the given QName. For example, a pattern facet matches 'facet xs: Get all the facets of the item, if any. Only simple types have facets. With access to types and their facets, as well as function lookup and function application, we can create a generic framework for processing dates without having to hardcode any type or function names.
XQuery fragment using schema annotations and function lookup to create a generic date-processing framework. Adding accessors to obtain element and attribute declarations from element and attribute nodes, and defining the component accessors over these new component types allows for these use cases.
In addition, the accessors already defined apply to these new declaration component values as well. Type test matching any element declaration value whose name matches the given QName, or which is in the substitution group with an element with the given QName as its head. Type test matching any attribute declaration value whose name matches the given QName. Fitting element declaration values into the type hierarchy leads us to go still further: Given that we already have element declaration values, it makes sense to expose the content model of a type in general.
Given that we already have attribute declaration values, it makes sense to expose the attributes declared on a complex type. The XML Schema component model creates some complexity in this area and we need to decide how to expose the information in the a usable way. That model makes a distinction between particles and terms, where the particle carries occurrence information.
It also makes an analogous distinction between attribute uses and attribute declarations, where attribute uses carry value constraints. Attribute uses and particles also can be used to carry local context-specific annotations. Return the particles within a model group or complex type's content type as values. It is difficult to generalize about different implementations of a language. Overall implementing the accessors, type tests and operators discussed here on top of an existing XQuery implementation was not difficult. XQuery is notoriously sensitive to syntactic extensions.
The use of functional syntax made the integration with an existing XQuery lexer and parser more straight-forward than it would have been if new syntactic constructs had been required. The new sequence type tests and the subtype of operator did require additions to the lexer and parser rules. The subtype of operator was added as an additional kind of comparison expression; the new sequence type tests were added in parallel to XPath kind tests. Adding the component kind tests required the same kind of special handling already required for other names that appear in a similar context, such as element or document-node.
These data structures were already present to support validation and type assignment. An implementation that lacked such data structures would clearly find exposing types as values more challenging.
It is unclear, however, whether a direct reflection of the schema component model is the right approach. It may be better to step back and design a cleaner API, and provide values over that model instead. Such a strategy would bring a higher implementation burden. Applying types as functions depended on a prior foundation of XQuery 3. Given that foundation, applying simple types as functions is trivial, and applying complex types as functions only slightly more so. The existing infrastructure to support schema validation was a necessary prerequisite to applying complex types as functions, however.
The most challenging part of the implementation was providing access to annotations. The existing data structures did not preserve annotations as data model instances, as they were irrelevant for validation and type assignment and there was no existing API that provided access to the schema components. A surprising amount of work needed to be done in order to preserve annotations and expose them as nodes. Finally, the experimental implementation actually did allow schema component values to be added as children to data model instances, primarily for debugging purposes. Adding a schema component value as a child added it as the XML Schema serialization.
About half the implementation code went into these debugging APIs. This paper has focused mainly on exposing types as values in XQuery with a few basic accessors, with some forays into some related schema components. Some meta-programming techniques rely on being able to examine the full richness of the schema component model — terms, particles, attribute uses, schema component affiliations, abstractness, and so on.
The program to provide such full access is similar to what was outlined here: More extensive additions to the syntax of XQuery to allow variables to be used as the operand of instance of and cast as expressions would improve usability further:. Once we embark on the program of providing full access to all the schema components and their properties, the use of schema component paths arises. Abbreviated syntax is defined for some path steps, and certain axes that skip over intermediate components can provide effective ways of navigating through content models, or selecting multiple components with a since path.
Schema component paths navigate through the schema component graph of an assembled schema. As with XPath, each step in the path consists of an axis combined with some kind of test and perhaps with a predicate. In schema component paths, the test is a name test possibly a wildcarded name test, and possibly a test for an anonymous component , and the only predicate defined is a positional predicate selecting the Nth of like components.
There are no accessors for non-component properties: About two dozen axes are defined, for each of the component-to-component relationships in the graph. For example, the annotation:: It then traverses the schemaElement axis schemaElement:: The path continues through the type axis type:: The path to this point will select the locally declared anonymous type of the element declaration 'outer'.
Finally the path concludes by traversing the schemaAttribute axis schemaAttribute:: As a whole then, this path selects a particular attribute declaration of a particular element declaration. The second path means the same thing, but uses abbreviated syntax. This time it traverses through the type axis type:: The path then traverses the model axis model:: The path continues along the schemaElement axis schemaElement:: Finally, the path traverses the type axis type:: The fourth path means the same thing, but uses abbreviated syntax.
How does this compare to the accessors we have defined above? The accessors operate not on components but on XQuery values. Some accessors, such as sc: To get the full range of axes available in schema component paths, it would be necessary to define an accessor function corresponding to each axis, and allow it to apply to component values.
To get the effect of the name tests, XPath predicates must be applied to the results of the accessor. Some accessors return simple properties of the components, such as its name. Schema component paths do not provide for access to the non-component properties. Since schema components are not nodes, XQuery forbids using them inside a path although they can be the last step of a path.
Since schema component accessors do not apply to schemas in isolation, it is not possible to construct XQuery expressions that are exactly equivalent to the schema component paths given previously. However, we can give some expressions that are roughly equivalent, to give some sense of how they compare. Schema component paths clearly express traversal through a schema component graph more compactly than the accessor and linkage functions do, in that they combine the accessor and the type test in one path step.
In addition, schema component paths generally elide the distinction between terms and particles, which the chained accessors do not. On the other hand, schema component paths do not provide a complete answer, however. They do not provide access to non-component information, nor do they bridge the boundary between schema components and nodes or other item types.
We could imagine allowing schema component paths to mix directly with normal XPath paths to provide that linkage.
Under this scheme the type axis in the fourth step of the path would start a relative schema component path with some component as the default. In this case, the context is the element declaration component for the title element. Mixing schema component paths with normal XPaths directly in this way is apt to be very confusing, however. The rules governing the slash are very different. In addition, abbreviated schema component paths in this mixed context confuses interpretation tremendously. Careful specification of the switching rules may eliminate ambiguities, but it won't eliminate confusion for humans reading and writing such paths.
The similarity of schema component paths to XPaths that helps make them more intuitive in isolation causes difficulty when used in the same context as XPath.
This confusion also makes implementation more difficult: Keeping schema component paths and XPaths clearly separated provides the power of both, without the confusion. Wrapping schema component paths within some kind of scoping expression and providing the rich set of accessor functions seems the best way to achieve this.
Schema component paths are wrapped inside special syntactic for to keep them clearly separated from normal XPaths. In summary, both schema component paths and the XQuery linkage and accessor functions both have their place. Schema component paths are suited to navigating through schema component graphs or pointing to specific schema components for schema analysis or reporting.
The accessor functions are more useful to exposing the schema information relevant to a particular XQuery item in the context of some operations over data. This paper has explored adding schema types as values into XQuery, providing some measure of structural type introspection.
In an XQuery context, a type is an XML Schema type, and to provide even basic structural type introspection requires pulling in quite a bit of the complexity of the XML schema component model. Nevertheless, implementation need not be too challenging, and only modest changes to the XQuery data model and existing syntax are required. It is possible to take an incremental approach to adding additional capabilities, but even some basic abilities can provide significant coding power and flexibility.
Schema component paths can be used in combination with linkage function if they are integrated with care, to avoid confusion.
Schema component paths satisfy use cases where deep analysis of the schema is required, while simple accessor and linkage functions work well for getting at basic metadata about the types of the data being operated on. Abstract Type introspection gives a program the ability to determine the type of object at runtime and manipulate the type of the object as an object in its own right. The Markup Conference Proceedings. How to cite this paper Holstege, Mary. The Markup Conference August 7 - 10, Introduction Type introspection gives a program the ability to determine the type of data item at runtime and manipulate the type as a data item in its own right.
Types as Values Where should XQuery meta-classes fit into the existing classes in the type hierarchy? Type values as component values, a new kind of item. Defining sequence type tests Defining the means to obtain type values from other values Determining how existing functions and operators apply to type values Defining useful functions and operators over type values Defining accessors on type values. Type Tests for Type Values For each kind of component value there is a sequence type test that matches values of that kind.
Types component Matches any component value. Obtaining Type Values Linkage functions get component values from various kinds of items. Accessors Linking from Items to Component Values sc: Get the type of the item as a value. Get the simple type of the item as a value. Get the complex type of the item as a value. Functions and Operators on Type Values Obtaining types as values is well and good, but what can we do with them other than perform sequence type tests on them? Implementing deep-equal with Type Values declare function my: Miscellaneous Introspection Functions sc: QName as type Return a type value for type with the given name, if any.
Type Values as Functions In XQuery, there is a constructor function for each in-scope named atomic type derived from a primitive type, whether the type is user-defined or built-in. A function can be defined to perform this typed-value fabrication operation: Types as functions sc: Example of applying a Type declare function local: Example of applying a type as an XQuery 3.
Using Type Introspection in Plugin Framework declare my: Component Accessors For true meta-programming, being able to access some of the details of the type components is important. Anyone who has worked at all in commercial practice knows how far it deviates from this idealization. It can easily happen that DevOps needs to patch together a little experiment to see what kind of performance it achieves, then … well, months later, someone notices that customers have come to depend on what was originally only a trial.
How do we deal with situations like this?
Get the database to tell you what it knows. Column or attribute type can not be displayed Use the database itself to help. Still more is possible. Does someone on your team think a particular code is a primary key in only three tables? Do you suspect that physical-file assignments have been made so inefficiently that read-write access is slower than it should be?