Converting Java values to XDM values

This section describes the general rules applied by Saxon for converting Java values to XDM values. These rules are used in a number of places, for example:

  • Converting the result of a Java extension function to a value that can be used in XPath expressions.

  • Conversion of the value supplied in a call to Transformer.setParameter() in the JAXP Transformation API.

  • Conversion of the value returned by a call to VariableResolver.resolver() in the JAXP XPath API.

  • Conversion of the first argument supplied in a call to XPathExpression.evaluate() in the JAXP XPath API (this argument supplies the context item. The JAXP documentation is written for XPath 1.0 where the context item is always a node, but Saxon extends it with support for later XPath versions, where this restriction is removed).

  • Conversion of the result of an external function implemented using the FunctionResolver mechanism in the JAXP XPath API.

In some of these contexts there are additional rules applied; for example the handling of a Java null varies. These variations are noted in the specific API documentation.

These conventions do not apply to APIs that define their own rules, for example the XQJ API for invoking XQuery. To achieve greater type safety, Saxon's s9api API generally requires explicit conversion of values rather than relying on implicit conversion rules.

    Conversion from Saxon-specific classes

    If the Java object is an instance of a Saxon-defined class, and the Saxon-defined class is an implementation of an XDM value, then the value will be accepted with no conversion.

    This includes the following cases:

    Converting atomic values

    This section describes Java classes that are recognized as equivalents to XDM atomic types.

    • If the Java value is a boolean or Boolean, the XPath result is an xs:boolean.

    • If the Java value is a double or Double, the XPath result is an xs:double.

    • If the Java value is a float or Float, the XPath result is an xs:float.

    • If the Java value is an int, short, long, byte, or one of their object wrapper equivalents, the XPath result is an instance of the corresponding subtype of xs:integer: for example a Java short produces an instance of xs:short.

    • If the Java value is a String, the XPath result is an xs:string. Unless otherwise specified, Saxon does not actually check that the characters in the Java string are legal XML characters.

    • If the Java value is a char or Character, it is converted to a single-character xs:string. Again, Saxon does not normally check that the value is a legal XML character.

    • Instances of the Java classes java.net.URI and java.net.URL are converted to instances of xs:anyURI by calling the toString() method on the supplied object.

    • An instance of javax.xml.namespace.QName is converted to an instance of xs:QName having the same prefix, namespace URI, and local part.

    • An instance of java.lang.BigInteger is converted to an instance of xs:integer with the same numeric value.

    • An instance of java.lang.BigDecimal is converted to an instance of xs:decimal with the same numeric value.

    • Java classes representing dates and times are converted as follows:

      • java.util.Date is converted to xs:dateTime by calling getTime() to convert to milliseconds since 1 Jan 1970. The resulting xs:dateTime value will be UTC.

      • java.time.Instant is converted to xs:dateTime with nanosecond precision. The resulting xs:dateTime value will be UTC.

      • java.time.OffsetDateTime is converted to an xs:dateTime with the same timezone offset, with nanosecond precision.

      • java.time.ZonedDateTime is first converted to an java.time.OffsetDateTime by calling toOffsetDateTime(), and this is then converted as described above.

      • java.time.LocalDateTime is converted to an xs:dateTime value with the same components (year, month, day, etc); the resulting xs:dateTime value will have no timezone component.

      • java.time.LocalDate is converted to an xs:dateTime value with the same components (year, month, day); the resulting xs:date value will have no timezone component.

    Converting nodes

    This section describes Java classes that are recognized as representing XDM Nodes.

    • If the supplied Java value is an instance of the Saxon class net.sf.saxon.om.NodeInfo (a node in a Saxon tree), the XPath value will be a sequence containing a single node.

    • If the supplied Java value is an instance of javax.xml.transform.Source (other than a NodeInfo), a tree is built from the specified Source object, and the XPath result is the root node of this tree.

    • If the supplied Java value is an instance of net.sf.saxon.om.TreeInfo then the root node of this tree is used.

    • If the supplied value is a DOM Node, and it is recognized as a wrapper around a Saxon node, then the node is unwrapped and the underlying Saxon node is returned. If the returned value is some other kind of DOM Node, then a Saxon wrapper is added. (This is an imperfect solution, since it can lead to problems with node identity and document order.)

    • If the supplied value is a DOM NodeList, the list of nodes is returned as a Saxon node-set. Each node is handled in the same way as a Node that is returned directly as the result.

    • If third party object models such as JDOM2, DOM4J, XOM, or AXIOM have been registered with the Saxon Configuration, then the Java classes representing nodes in these various object models are recognized. The supplied node will be wrapped as an XDM node, which does not involve copying, so relationships among nodes in the same tree are preserved.

    Converting sequences

    Java collections are converted to XDM sequences:

    • If the returned value is an instance of the Java class java.util.Collection, or if it is an array, the XPath value will be the sequence represented by the contents of this Collection or array. The members of the collection or array will each be converted to an XPath value, by applying these rules recursively. An error is reported if the result contains a list or array nested within another list or array. The contents of the list or array are copied immediately on return from the function, so the original List or array object itself may be safely re-used.

    • There is an exception to this rule where the return type is defined as byte[]. Partly for historical reasons, and partly to reflect the fact that a byte[] array is often used to represent binary data in the form of a sequence of octets, a byte[] value is converted to a sequence of xs:unsignedByte items, each in the range 0..255.

    Note that Java maps (instances of java.util.Map are not converted to XDM maps. Such a conversion can be achieved using the static factory method XdmMap.makeMap().

    Wrapped Java objects

    If the supplied value is any other Java object, it is returned as a "wrapped Java object". The required type for a wrapped object of Java class java.util.Map is written using the QName jt:java.util.Map, where the namespace prefix jt represents the namespace http://saxon.sf.net/java-type.