@NbBundle.Messages({
    "# {0} - attribute name",
    "ERR_lowercasePropertyName=Invalid property name: {0}. Property name, or the last component of a static property name must start with lowercase.",
    "# {0} - attribute name",
    "ERR_invalidReservedPropertyName=Unknown name in FXML reserved namespace: {0}",
    "# {0} - attribute qname",
    "# {1} - tag name",
    "ERR_unsupportedAttribute=Unsupported attribute {0} on {1}"
  })
  private void processInstanceAttributes(Attributes atts) {
    for (int i = 0; i < atts.getLength(); i++) {
      String uri = atts.getURI(i);
      String name = atts.getLocalName(i);
      String qname = atts.getQName(i);

      PropertySetter ps = null;

      FxNode node;

      if (qname.startsWith("xmlns")) { // NOI18N
        // FIXME - xmlns attributes will be represented as FxNodes :-/
        continue;
      }

      if (FXML_FX_NAMESPACE.equals(uri)) {
        if (!(FX_ID.equals(name)
            || FX_CONTROLLER.equals(name)
            || FX_VALUE.equals(name)
            || FX_FACTORY.contains(name))) {
          addAttributeError(
              qname,
              "error-unsupported-attribute",
              ERR_unsupportedAttribute(qname, tagName),
              qname,
              tagName);
        }
        continue;
      }

      if (current instanceof FxInstanceCopy) {
        if (FxXmlSymbols.FX_ATTR_REFERENCE_SOURCE.equals(name) && uri == null) {
          // ignore source in fx:copy
          continue;
        }
      }

      // if the name begins with "on", it's an event handler.
      if (name.startsWith(EVENT_HANDLER_PREFIX) && name.length() > EVENT_HANDLER_PREFIX_LEN) {
        String en =
            Character.toLowerCase(name.charAt(EVENT_HANDLER_PREFIX_LEN))
                + name.substring(EVENT_HANDLER_PREFIX_LEN + 1);
        node = processEventHandlerAttribute(en, atts.getValue(i));
        // special hack for fx:copy or fx:reference
      } else {
        // FIXME - error detection for static property
        int stProp = FxXmlSymbols.findStaticProperty(name);
        if (stProp == -2) {
          // report error, not a well formed property name.
          addAttributeError(qname, "invalid-property-name", ERR_lowercasePropertyName(name), name);
          node = accessor.makeBroken(accessor.createProperty(name, false));
        } else if (stProp == -1) {
          // this is a normal property
          node = ps = accessor.createProperty(name, false);
        } else {
          // it is a static property
          node =
              ps =
                  accessor.createStaticProperty(
                      name.substring(stProp + 1), name.substring(0, stProp));
        }
        if (ps != null) {
          accessor.addContent(ps, atts.getValue(i));
          node = ps;
        }
      }
      initAttribute(node, qname);
      attachProperty(ps);
      attachChildNode(node);
    }
  }
  @NbBundle.Messages({
    "# {0} - tag name",
    "ERR_tagNotJavaIdentifier=Invalid class name: {0}",
    "# {0} - tag name",
    "ERR_fxControllerPermittedOnRoot=fx:controller is not permitted on tag {0}. Can be only present on root element."
  })
  private FxNewInstance handleClassTag(String localName, Attributes atts) {
    String fxValueContent = null;
    String fxFactoryContent = null;
    String fxId = null;

    int off = contentLocator.getElementOffset() + 1; // the <

    for (int i = 0; i < atts.getLength(); i++) {
      String uri = atts.getURI(i);
      if (!FXML_FX_NAMESPACE.equals(uri)) {
        // no special attribute
        continue;
      }
      String name = atts.getLocalName(i);
      if (FX_VALUE.equals(name)) {
        fxValueContent = atts.getValue(i);
      } else if (FX_FACTORY.equals(name)) {
        fxFactoryContent = atts.getValue(i);
      } else if (FX_ID.equals(name)) {
        fxId = atts.getValue(i);
      } else if (FX_CONTROLLER.equals(name)) {
        if (nodeStack.peek().getKind() != Kind.Source) {
          addAttributeError(
              atts.getQName(i),
              "fx-controller-permitted-on-root",
              ERR_fxControllerPermittedOnRoot(localName),
              localName);
        } else {
          controllerName = atts.getValue(i);
        }
      } else {
        addAttributeError(
            atts.getQName(i),
            "invalid-property-reserved-name",
            ERR_invalidReservedPropertyName(name),
            name);
      }
    }

    // first we must check how this class tag is created.
    FxNewInstance instance =
        accessor.createInstance(localName, fxValueContent, fxFactoryContent, fxId);

    if (!FxXmlSymbols.isQualifiedIdentifier(localName)) {
      // not a java identifier, error
      addError(
          new ErrorMark(
              off,
              localName.length(),
              "invalid-class-name",
              ERR_tagNotJavaIdentifier(localName),
              localName));
      accessor.makeBroken(instance);
      return instance;
    }

    return instance;
  }