All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.saxon.tree.linked.ElementImpl Maven / Gradle / Ivy

There is a newer version: 12.5
Show newest version
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2018-2023 Saxonica Limited
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package net.sf.saxon.tree.linked;

import net.sf.saxon.event.CopyNamespaceSensitiveException;
import net.sf.saxon.event.Receiver;
import net.sf.saxon.event.ReceiverOption;
import net.sf.saxon.expr.parser.Loc;
import net.sf.saxon.om.*;
import net.sf.saxon.pattern.NodeKindTest;
import net.sf.saxon.pattern.NodeSelector;
import net.sf.saxon.pattern.NodeTest;
import net.sf.saxon.s9api.Location;
import net.sf.saxon.str.UnicodeString;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.tree.iter.AxisIterator;
import net.sf.saxon.tree.util.Navigator;
import net.sf.saxon.type.*;
import net.sf.saxon.value.AtomicValue;
import net.sf.saxon.value.Whitespace;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;

/**
 * ElementImpl implements an element node in the Linked tree model. Subclasses of ElementImpl,
 * for holding particular kinds of element, can be defined by using a {@link NodeFactory}
 * registered with the {@link LinkedTreeBuilder} used to construct the tree.
 */


public class ElementImpl extends ParentNodeImpl implements NamespaceResolver {

    private NodeName nodeName;
    private SchemaType type = Untyped.getInstance();
    private AttributeMap attributeMap;      // this excludes namespace attributes
    private NamespaceMap namespaceMap = NamespaceMap.emptyMap();

    /**
     * Construct an empty ElementImpl
     */

    public ElementImpl() {
        this.attributeMap = EmptyAttributeMap.getInstance();
    }

    /**
     * Set the attribute list
     *
     * @param atts the list of attributes of this element (not including namespace attributes)
     */

    @Override
    public void setAttributes(AttributeMap atts) {
        this.attributeMap = atts;
    }

    /**
     * Set the node name
     *
     * @param name the node name
     */

    public void setNodeName(NodeName name) {
        this.nodeName = name;
    }

    /**
     * Initialise a new ElementImpl with an element name
     *
     * @param elemName       Integer representing the element name, with namespaces resolved
     * @param elementType    the schema type of the element node
     * @param atts           The attribute list: always null
     * @param parent         The parent node
     * @param sequenceNumber Integer identifying this element within the document
     */

    public void initialise(/*@NotNull*/ NodeName elemName, SchemaType elementType, AttributeMap atts, /*@NotNull*/ NodeInfo parent,
                                        int sequenceNumber) {
        this.nodeName = elemName;
        this.type = elementType;
        setRawParent((ParentNodeImpl) parent);
        setRawSequenceNumber(sequenceNumber);
        attributeMap = atts;
    }

    /**
     * Get the name of the node. Returns null for an unnamed node
     *
     * @return the name of the node
     */
    @Override
    public NodeName getNodeName() {
        return nodeName;
    }

    /**
     * Set location information for this node
     *
     * @param systemId the base URI
     * @param line     the line number if known
     * @param column   the column number if known
     */

    public void setLocation(String systemId, int line, int column) {
        DocumentImpl root = getRawParent().getPhysicalRoot();
        root.setLineAndColumn(getRawSequenceNumber(), line, column);
        root.setSystemId(getRawSequenceNumber(), systemId);
    }

    /**
     * Set the system ID of this node. This method is provided so that a NodeInfo
     * implements the javax.xml.transform.Source interface, allowing a node to be
     * used directly as the Source of a transformation
     */

    @Override
    public void setSystemId(String uri) {
        getPhysicalRoot().setSystemId(getRawSequenceNumber(), uri);
    }

    /**
     * Get the root node
     */

    @Override
    public NodeInfo getRoot() {
        ParentNodeImpl up = getRawParent();
        if (up == null || (up instanceof DocumentImpl && ((DocumentImpl) up).isImaginary())) {
            return this;
        } else {
            return up.getRoot();
        }
    }

    /**
     * Get the system ID of the entity containing this element node.
     */

    /*@Nullable*/
    @Override
    public final String getSystemId() {
        DocumentImpl root = getPhysicalRoot();
        return root == null ? null : root.getSystemId(getRawSequenceNumber());
    }

    /**
     * Get the base URI of this element node. This will be the same as the System ID unless
     * xml:base has been used.
     */

    @Override
    public String getBaseURI() {
        return Navigator.getBaseURI(this, n -> getPhysicalRoot().isTopWithinEntity((ElementImpl) n));
    }

    /**
     * Determine whether the node has the is-nilled property
     *
     * @return true if the node has the is-nilled property
     */

    @Override
    public boolean isNilled() {
        return getPhysicalRoot().isNilledElement(this);
    }

    /**
     * Set the type annotation on a node. This must only be called when the caller has verified (by validation)
     * that the node is a valid instance of the specified type. The call is ignored if the node is not an element
     * or attribute node.
     *
     * @param type the type annotation
     */

    @Override
    public void setTypeAnnotation(SchemaType type) {
        this.type = type;
    }

    /**
     * Say that the element has the nilled property
     */

    public void setNilled() {
        getPhysicalRoot().addNilledElement(this);
    }

    /**
     * Get the type annotation
     *
     * @return the type annotation of the node
     */

    @Override
    public SchemaType getSchemaType() {
        return type;
    }

    /**
     * Get the line number of the node within its source document entity
     */

    @Override
    public int getLineNumber() {
        DocumentImpl root = getPhysicalRoot();
        if (root == null) {
            return -1;
        } else {
            return root.getLineNumber(getRawSequenceNumber());
        }
    }

    /**
     * Get the line number of the node within its source document entity
     */

    @Override
    public int getColumnNumber() {
        DocumentImpl root = getPhysicalRoot();
        if (root == null) {
            return -1;
        } else {
            return root.getColumnNumber(getRawSequenceNumber());
        }
    }

    /**
     * Get a character string that uniquely identifies this node
     *
     * @param buffer to contain the generated ID
     */

    @Override
    public void generateId(/*@NotNull*/ StringBuilder buffer) {
        int sequence = getRawSequenceNumber();
        if (sequence >= 0) {
            getPhysicalRoot().generateId(buffer);
            buffer.append("e");
            buffer.append(sequence);
        } else {
            getRawParent().generateId(buffer);
            buffer.append("f");
            buffer.append(getSiblingPosition());
        }
    }

    /**
     * Return the kind of node.
     *
     * @return Type.ELEMENT
     */

    @Override
    public final int getNodeKind() {
        return Type.ELEMENT;
    }

    /**
     * Get the attributes of the element
     *
     * @return an attribute map containing the attributes of the element
     */

    @Override
    public AttributeMap attributes() {
        return attributeMap;
    }

    AxisIterator iterateAttributes(NodeTest test) {
        if (attributeMap instanceof AttributeMapWithIdentity) {
            // this case needs special care because of the possibility of deleted attribute nodes
            return new Navigator.AxisFilter(((AttributeMapWithIdentity) attributeMap).iterateAttributes(this), test);
        } else {
            return new AttributeAxisIterator(this, test);
        }
    }

    /**
     * Copy this node to a given Receiver.
     * 

This method is primarily for internal use. It should not be considered a stable * part of the Saxon API.

* * @param out the Receiver to which the node should be copied. It is the caller's * responsibility to ensure that this Receiver is open before the method is called * (or that it is self-opening), and that it is closed after use. * @param copyOptions a selection of the options defined in {@link CopyOptions} * @param location If non-null, identifies the location of the instruction * that requested this copy. If zero, indicates that the location information * is not available * @throws XPathException if any downstream error occurs */ @Override public void copy(Receiver out, int copyOptions, Location location) throws XPathException { final boolean copyTypes = CopyOptions.includes(copyOptions, CopyOptions.TYPE_ANNOTATIONS); final boolean copyForUpdate = CopyOptions.includes(copyOptions, CopyOptions.FOR_UPDATE); SchemaType typeCode = copyTypes ? getSchemaType() : Untyped.getInstance(); java.util.function.Function informee = out.getPipelineConfiguration().getCopyInformee(); if (informee != null) { Object o = informee.apply(this); if (o instanceof Location) { location = (Location) o; } } NamespaceMap ns = CopyOptions.includes(copyOptions, CopyOptions.ALL_NAMESPACES) ? getAllNamespaces() : NamespaceMap.emptyMap(); boolean disallowNamespaceSensitiveContent = ((copyOptions & CopyOptions.TYPE_ANNOTATIONS) != 0) && ((copyOptions & CopyOptions.ALL_NAMESPACES) == 0); if (copyTypes && disallowNamespaceSensitiveContent) { try { checkNotNamespaceSensitiveElement(getSchemaType()); } catch (CopyNamespaceSensitiveException e) { e.setErrorCode(out.getPipelineConfiguration().isXSLT() ? "XTTE0950" : "XQTY0086"); throw e; } } List atts = new ArrayList<>(attributes().size()); for (AttributeInfo att : attributes()) { SimpleType attributeType = BuiltInAtomicType.UNTYPED_ATOMIC; if (copyTypes) { attributeType = att.getType(); if (disallowNamespaceSensitiveContent) { try { checkNotNamespaceSensitiveAttribute(attributeType, att); } catch (CopyNamespaceSensitiveException e) { e.setErrorCode(out.getPipelineConfiguration().isXSLT() ? "XTTE0950" : "XQTY0086"); throw e; } } } atts.add(new AttributeInfo(att.getNodeName(), attributeType, att.getValue(), att.getLocation(), 0)); } int receiverOptions = ReceiverOption.BEQUEATH_INHERITED_NAMESPACES_ONLY | ReceiverOption.NAMESPACE_OK; if (copyForUpdate) { receiverOptions |= ReceiverOption.MUTABLE_TREE; } out.startElement(NameOfNode.makeName(this), typeCode, SequenceTool.attributeMapFromList(atts), ns, location, receiverOptions); // output the children NodeImpl next = getFirstChild(); while (next != null) { next.copy(out, copyOptions, location); next = next.getNextSibling(); } out.endElement(); } /** * Check whether the content of this element is namespace-sensitive * * @param type the type annotation of the node * @throws XPathException if an error occurs */ protected void checkNotNamespaceSensitiveElement(SchemaType type) throws XPathException { if (type instanceof SimpleType && ((SimpleType) type).isNamespaceSensitive()) { if (type.isAtomicType()) { throw new CopyNamespaceSensitiveException( "Cannot copy QName or NOTATION values without copying namespaces"); } else { // For a union or list type, we need to check whether the actual value is namespace-sensitive AtomicSequence value = atomize(); for (AtomicValue val : value) { if (val.getPrimitiveType().isNamespaceSensitive()) { throw new CopyNamespaceSensitiveException( "Cannot copy QName or NOTATION values without copying namespaces"); } } } } } /** * Check whether the content of an attribute is namespace-sensitive * * @param type the type annotation of the attribute node * @param att the attribute * @throws XPathException if the content is namespace sensitive and cannot be copied */ private void checkNotNamespaceSensitiveAttribute(SimpleType type, AttributeInfo att) throws XPathException { if (type.isNamespaceSensitive()) { if (type.isAtomicType()) { throw new CopyNamespaceSensitiveException( "Cannot copy QName or NOTATION values without copying namespaces"); } else { // For a union or list type, we need to check whether the actual value is namespace-sensitive AtomicSequence value = type.getTypedValue(att.getXdmStringValue().getUnicodeStringValue(), namespaceMap, getConfiguration().getConversionRules()); for (AtomicValue val : value) { if (val.getPrimitiveType().isNamespaceSensitive()) { throw new CopyNamespaceSensitiveException( "Cannot copy QName or NOTATION values without copying namespaces"); } } } } } /** * Delete this node (that is, detach it from its parent) */ @Override public void delete() { DocumentImpl root = getPhysicalRoot(); super.delete(); if (root != null) { AxisIterator iter = iterateAxis(AxisInfo.DESCENDANT_OR_SELF, NodeKindTest.ELEMENT); while (true) { ElementImpl n = (ElementImpl) iter.next(); for (AttributeInfo att : attributeMap) { if (att.isId()) { root.deregisterID(att.getValue()); } } if (n == null) { break; } root.deIndex(n); } } } /** * Rename this node * * @param newName the new name * @param inherit true if any new namespace binding is to be inherited */ @Override public void rename(NodeName newName, boolean inherit) { String prefix = newName.getPrefix(); NamespaceUri uri = newName.getNamespaceUri(); NamespaceBinding ns = new NamespaceBinding(prefix, uri); NamespaceUri uc = getURIForPrefix(prefix, true); if (uc == null) { uc = NamespaceUri.NULL; } if (!uc.equals(uri)) { if (uc.isEmpty()) { addNamespace(ns, inherit); } else { throw new IllegalArgumentException( "Namespace binding of new name conflicts with existing namespace binding"); } } nodeName = newName; } /** * Add a namespace binding (that is, a namespace node) to this element. This call has no effect if applied * to a node other than an element. * * @param binding The namespace binding to be * added. If the target element already has a namespace binding with this (prefix, uri) pair, the call has * no effect. If the target element currently has a namespace binding with this prefix and a different URI, an * exception is raised. * @param inherit true if the namespace is to be inherited by descendant elements */ @Override public void addNamespace(/*@NotNull*/ NamespaceBinding binding, boolean inherit) { if (binding.getNamespaceUri().isEmpty()) { throw new IllegalArgumentException("Cannot add a namespace undeclaration"); } NamespaceUri existing = namespaceMap.getNamespaceUri(binding.getPrefix()); if (existing != null) { if (!existing.equals(binding.getNamespaceUri())) { throw new IllegalArgumentException("New namespace conflicts with existing namespace binding"); } } else { NamespaceMap oldMap = namespaceMap; namespaceMap = namespaceMap.put(binding.getPrefix(), binding.getNamespaceUri()); if (inherit && namespaceMap != oldMap) { for (NodeInfo child : children(NodeKindTest.ELEMENT)) { ((ElementImpl) child).inheritParentNamespaces(binding, oldMap, namespaceMap); } } } } private void inheritParentNamespaces(NamespaceBinding binding, NamespaceMap oldParentMap, NamespaceMap newParentMap) { NamespaceMap oldMap = namespaceMap; if (oldMap.getURIForPrefix(binding.getPrefix(), false) == null) { if (namespaceMap == oldParentMap) { namespaceMap = newParentMap; } else { namespaceMap = namespaceMap.put(binding.getPrefix(), binding.getNamespaceUri()); } for (NodeInfo child : children(NodeKindTest.ELEMENT)) { ((ElementImpl) child).inheritParentNamespaces(binding, oldMap, namespaceMap); } } } /** * Replace the string-value of this node * * @param stringValue the new string value */ @Override public void replaceStringValue(/*@NotNull*/ UnicodeString stringValue) { if (stringValue.isEmpty()) { setChildren(null); } else { TextImpl text = new TextImpl(stringValue); text.setRawParent(this); setChildren(text); } } /** * Change details of an attribute of this element * * @param index the index position of the attribute to be changed * @param attInfo new details of the attribute */ public void setAttributeInfo(int index, AttributeInfo attInfo) { AttributeMapWithIdentity attMap = prepareAttributesForUpdate(); attMap = attMap.set(index, attInfo); setAttributes(attMap); } private AttributeMapWithIdentity prepareAttributesForUpdate() { if (attributes() instanceof AttributeMapWithIdentity) { return (AttributeMapWithIdentity) attributes(); } else { AttributeMapWithIdentity newAtts = new AttributeMapWithIdentity(attributes().asList()); setAttributes(newAtts); return newAtts; } } /** * Add an attribute to this element node. *

If this node is not an element, or if the supplied node is not an attribute, the method * takes no action. If the element already has an attribute with this name, the method * throws an exception.

*

This method does not perform any namespace fixup. It is the caller's responsibility * to ensure that any namespace prefix used in the name of the attribute (or in its value * if it has a namespace-sensitive type) is declared on this element.

* * @param nodeName the name of the new attribute * @param attType the type annotation of the new attribute * @param value the string value of the new attribute * @param properties properties including IS_ID and IS_IDREF properties * @param inheritNamespaces true if any namespace used by this attribute name is to be inherited by descendant elements * @throws IllegalStateException if the element already has an attribute with the given name. */ @Override public void addAttribute(/*@NotNull*/ NodeName nodeName, SimpleType attType, /*@NotNull*/ String value, int properties, boolean inheritNamespaces) { AttributeMapWithIdentity atts = prepareAttributesForUpdate(); atts = atts.add(new AttributeInfo(nodeName, attType, value, Loc.NONE, ReceiverOption.NONE)); setAttributes(atts); if (!nodeName.hasURI(NamespaceUri.NULL)) { // The new attribute name is in a namespace NamespaceBinding binding = nodeName.getNamespaceBinding(); String prefix = binding.getPrefix(); NamespaceUri uc = getURIForPrefix(prefix, false); if (uc == null) { // The namespace is not already declared on the element addNamespace(binding, inheritNamespaces); } else if (!uc.equals(binding.getNamespaceUri())) { throw new IllegalStateException( "Namespace binding of new name conflicts with existing namespace binding"); } } if (ReceiverOption.contains(properties, ReceiverOption.IS_ID)) { DocumentImpl root = getPhysicalRoot(); if (root != null) { root.registerID(this, Whitespace.trim(value)); } } } /** * Remove an attribute from this element node *

If this node is not an element, or if the specified node is not an attribute * of this element, this method takes no action.

*

The attribute object itself becomes unusable; any attempt to use this attribute object, * or any other object representing the same node, is likely to result in an exception.

* * @param attribute the attribute node to be removed */ @Override public void removeAttribute(/*@NotNull*/ NodeInfo attribute) { if (!(attribute instanceof AttributeImpl)) { return; // no action } int index = ((AttributeImpl) attribute).getSiblingPosition(); AttributeInfo info = attributes().itemAt(index); AttributeMapWithIdentity atts = prepareAttributesForUpdate(); atts = atts.remove(index); setAttributes(atts); if (index >= 0 && info.isId()) { DocumentImpl root = getPhysicalRoot(); root.deregisterID(info.getValue()); } ((AttributeImpl) attribute).setRawParent(null); } /** * Remove a namespace node from this node. The namespaces of its descendant nodes are unaffected. * The method has no effect on non-element nodes, nor on elements if there is no in-scope namespace * with the required prefix, nor if the element name or one of its attributes uses this namespace * prefix * * @param prefix the namespace prefix. */ @Override public void removeNamespace(String prefix) { Objects.requireNonNull(prefix); if (prefix.equals(getPrefix())) { throw new IllegalStateException("Cannot remove binding of namespace prefix used on the element name"); } for (AttributeInfo att : attributeMap) { if (att.getNodeName().getPrefix().equals(prefix)) { throw new IllegalStateException("Cannot remove binding of namespace prefix used on an existing attribute name"); } } namespaceMap = namespaceMap.remove(prefix); } /** * Add a namespace node from this node. The namespaces of its descendant nodes are unaffected. * The method has no effect on non-element nodes. If there is an existing namespace using this * prefix, the method throws an exception. * @param prefix the namespace prefix. Empty string for the default namespace. * @param uri The namespace URI. */ @Override public void addNamespace(String prefix, NamespaceUri uri) { NamespaceUri existingURI = namespaceMap.getNamespaceUri(prefix); if (existingURI == null) { namespaceMap = namespaceMap.put(prefix, uri); } else if (!existingURI.equals(uri)) { throw new IllegalStateException( "New namespace binding conflicts with existing namespace binding"); } } /** * Remove type information from this node (and its ancestors, recursively). * This method implements the upd:removeType() primitive defined in the XQuery Update specification */ @Override public void removeTypeAnnotation() { if (getSchemaType() != Untyped.getInstance()) { type = AnyType.getInstance(); getRawParent().removeTypeAnnotation(); } } public void setNamespaceMap(NamespaceMap map) { namespaceMap = map; } /** * Get the namespace URI corresponding to a given prefix. Return null * if the prefix is not in scope. * * @param prefix the namespace prefix. May be the zero-length string, indicating * that there is no prefix. This indicates either the default namespace or the * null namespace, depending on the value of useDefault. * @param useDefault true if the default namespace is to be used when the * prefix is "". If false, the method returns "" when the prefix is "". * @return the uri for the namespace, or null if the prefix is not in scope. * The "null namespace" is represented by the pseudo-URI "". */ /*@Nullable*/ @Override public NamespaceUri getURIForPrefix(/*@NotNull*/ String prefix, boolean useDefault) { if (prefix.isEmpty()) { if (useDefault) { return namespaceMap.getDefaultNamespace(); } else { return NamespaceUri.NULL; } } else { return namespaceMap.getNamespaceUri(prefix); } } /** * Get an iterator over all the prefixes declared in this namespace context. This will include * the default namespace (prefix="") and the XML namespace where appropriate */ /*@Nullable*/ @Override public Iterator iteratePrefixes() { return namespaceMap.iteratePrefixes(); } /** * Search the in-scope namespaces to see whether a given namespace is in scope. * * @param uri The URI to be matched. * @return true if the namespace is in scope */ /*@Nullable*/ public boolean isInScopeNamespace(/*@NotNull*/ NamespaceUri uri) { for (NamespaceBinding b : namespaceMap) { if (b.getNamespaceUri().equals(uri)) { return true; } } return false; } /** * Get all namespace undeclarations and undeclarations defined on this element. * * @param buffer If this is non-null, and the result array fits in this buffer, then the result * may overwrite the contents of this array, to avoid the cost of allocating a new array on the heap. * @return An array of NamespaceBinding objects representing the namespace declarations and undeclarations present on * this element. For a node other than an element, return null. * The XML namespace is never included in the list. If the supplied array is larger than required, * then the first unused entry will be set to null. *

For a node other than an element, the method returns null.

*/ @Override public NamespaceBinding[] getDeclaredNamespaces(NamespaceBinding[] buffer) { List bindings = new ArrayList<>(); for (NamespaceBinding nb : namespaceMap) { bindings.add(nb); } return bindings.toArray(NamespaceBinding.EMPTY_ARRAY); } /** * Ensure that a child element being inserted into a tree has the right namespace declarations. * Redundant declarations should be removed. If the child is in the null namespace but the parent has a default * namespace, xmlns="" should be added. If inherit is false, namespace undeclarations should be added for all * namespaces that are declared on the parent but not on the child. * * @param inherit true if the child is to inherit the inscope namespaces of its new parent */ protected void fixupInsertedNamespaces(boolean inherit) { if (getRawParent().getNodeKind() == Type.DOCUMENT) { return; } ElementImpl parent = (ElementImpl) getRawParent(); NamespaceMap parentNamespaces = parent.namespaceMap; // Namespaces present on the parent but not on the child should be undeclared (if requested) if (inherit) { deepAddNamespaces(parentNamespaces); } } private void deepAddNamespaces(NamespaceMap inheritedNamespaces) { NamespaceMap childNamespaces = namespaceMap; for (NamespaceBinding binding : inheritedNamespaces) { if (childNamespaces.getNamespaceUri(binding.getPrefix()) == null) { childNamespaces = childNamespaces.put(binding.getPrefix(), binding.getNamespaceUri()); } else { inheritedNamespaces = inheritedNamespaces.remove(binding.getPrefix()); } } namespaceMap = childNamespaces; for (NodeInfo child : children(NodeSelector.of(ElementImpl.class::isInstance))) { ((ElementImpl) child).deepAddNamespaces(inheritedNamespaces); } } /** * Get the namespace list for this element. * * @return The full set of in-scope namespaces */ /*@Nullable*/ @Override public NamespaceMap getAllNamespaces() { return namespaceMap; } /** * Get the value of a given attribute of this node * * @param uri the namespace URI of the attribute name, or {@link NamespaceUri#NULL} * if the attribute is not in a namespace * @param localName the local part of the attribute name * @return the attribute value if it exists or null if not */ /*@Nullable*/ @Override public String getAttributeValue(/*@NotNull*/ NamespaceUri uri, /*@NotNull*/ String localName) { return attributeMap == null ? null : attributeMap.getValue(uri, localName); } /** * Determine whether this node has the is-id property * * @return true if the node is an ID */ @Override public boolean isId() { // This is an approximation. For a union type, we check that the actual value is a valid NCName, // but we don't check that it was validated against the member type of the union that is an ID type. try { SchemaType type = getSchemaType(); return type.getFingerprint() == StandardNames.XS_ID || type.isIdType() && NameChecker.isValidNCName(getUnicodeStringValue().codePoints()); } catch (MissingComponentException e) { return false; } } /** * Ask whether this node has the is-idref property * * @return true if the node is an IDREF or IDREFS element. */ @Override public boolean isIdref() { return isIdRefNode(this); } public static boolean isIdRefNode(NodeImpl node) { SchemaType type = node.getSchemaType(); try { if (type.isIdRefType()) { if (type == BuiltInAtomicType.IDREF || type == BuiltInListType.IDREFS) { return true; } try { for (AtomicValue av : node.atomize()) { if (av.getItemType().isIdRefType()) { return true; } } } catch (XPathException err) { // no action } } } catch (MissingComponentException e) { return false; } return false; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy