/**
   * Creates an instance of {@link RepeaterJXPathBinding} according to the attributes and nested
   * comfiguration elements of the bindingElm.
   *
   * @param bindingElm
   * @param assistant
   * @return JXPathBindingBase
   */
  public JXPathBindingBase buildBinding(
      Element bindingElm, JXPathBindingManager.Assistant assistant) throws BindingException {

    try {
      CommonAttributes commonAtts = JXPathBindingBuilderBase.getCommonAttributes(bindingElm);

      String repeaterId = DomHelper.getAttribute(bindingElm, "id");
      String parentPath = DomHelper.getAttribute(bindingElm, "parent-path");
      String rowPath = DomHelper.getAttribute(bindingElm, "row-path");
      String rowPathForInsert = DomHelper.getAttribute(bindingElm, "row-path-insert", rowPath);
      String uniqueRowId = DomHelper.getAttribute(bindingElm, "unique-row-id", null);
      String uniqueRowIdPath = DomHelper.getAttribute(bindingElm, "unique-path", null);

      Convertor convertor = null;
      Locale convertorLocale = Locale.US;
      Element convertorEl = DomHelper.getChildElement(bindingElm, Constants.WD_NS, "convertor");
      if (convertorEl != null) {
        String datatype = DomHelper.getAttribute(convertorEl, "datatype");
        String localeStr = convertorEl.getAttribute("datatype");
        if (!localeStr.equals("")) {
          convertorLocale = I18nUtils.parseLocale(localeStr);
        }
        convertor = assistant.getDatatypeManager().createConvertor(datatype, convertorEl);
      }

      Element childWrapElement =
          DomHelper.getChildElement(bindingElm, BindingManager.NAMESPACE, "on-bind");
      if (childWrapElement == null) {
        throw new BindingException(
            "RepeaterBinding misses '<on-bind>' child definition. "
                + DomHelper.getLocation(bindingElm));
      }
      JXPathBindingBase[] childBindings = assistant.makeChildBindings(childWrapElement);

      Element deleteWrapElement =
          DomHelper.getChildElement(bindingElm, BindingManager.NAMESPACE, "on-delete-row");
      JXPathBindingBase[] deleteBindings = null;
      if (deleteWrapElement != null) {
        deleteBindings = assistant.makeChildBindings(deleteWrapElement);
      }

      Element insertWrapElement =
          DomHelper.getChildElement(bindingElm, BindingManager.NAMESPACE, "on-insert-row");
      JXPathBindingBase insertBinding = null;
      if (insertWrapElement != null) {
        insertBinding = assistant.makeChildBindings(insertWrapElement)[0];
      }
      /* New <wb:unique-row> child element builder */
      Element uniqueFieldWrapElement =
          DomHelper.getChildElement(bindingElm, BindingManager.NAMESPACE, "unique-row");
      JXPathBindingBase[] uniqueFieldBinding = null;
      if (uniqueFieldWrapElement != null) {
        uniqueFieldBinding = assistant.makeChildBindings(uniqueFieldWrapElement);
      } else if (uniqueRowId == null || uniqueRowIdPath == null) {
        throw new BindingException(
            "RepeaterBinding misses '<unique-row>' child definition. "
                + DomHelper.getLocation(bindingElm));
      } else {
        if (this.getLogger().isInfoEnabled()) {
          this.getLogger()
              .info(
                  "<wb:repeater>: The attributes 'unique-row-id' and "
                      + "'unique-path' are deprecated. Use <unique-row> child element instead."
                      + " Located at "
                      + DomHelper.getLocation(bindingElm));
        }
      }

      RepeaterJXPathBinding repeaterBinding =
          new RepeaterJXPathBinding(
              commonAtts,
              repeaterId,
              parentPath,
              rowPath,
              rowPathForInsert,
              uniqueRowId,
              uniqueRowIdPath,
              convertor,
              convertorLocale,
              childBindings,
              insertBinding,
              deleteBindings,
              uniqueFieldBinding);
      return repeaterBinding;
    } catch (BindingException e) {
      throw e;
    } catch (Exception e) {
      throw new BindingException(
          "Error building repeater binding defined at " + DomHelper.getLocation(bindingElm), e);
    }
  }
  public Convertor build(Element configElement) throws Exception {
    FormattingDateConvertor convertor = new FormattingDateConvertor();

    if (configElement == null) return convertor;

    String style = configElement.getAttribute("style");
    if (!style.equals("")) {
      if (style.equals("short")) convertor.setStyle(DateFormat.SHORT);
      else if (style.equals("medium")) convertor.setStyle(DateFormat.MEDIUM);
      else if (style.equals("long")) convertor.setStyle(DateFormat.LONG);
      else if (style.equals("full")) convertor.setStyle(DateFormat.FULL);
      else
        throw new Exception(
            "Invalid value \""
                + style
                + "\" for style attribute at "
                + DomHelper.getLocation(configElement));
    }

    String variant = configElement.getAttribute("variant");
    if (!variant.equals("")) {
      if (variant.equals(FormattingDateConvertor.DATE)
          || variant.equals(FormattingDateConvertor.TIME)
          || variant.equals(FormattingDateConvertor.DATE_TIME)) {
        convertor.setVariant(variant);
      } else {
        throw new Exception(
            "Invalid value \""
                + variant
                + "\" for variant attribute at "
                + DomHelper.getLocation(configElement));
      }
    }

    String lenient = configElement.getAttribute("lenient");
    if (!lenient.equals("")) {
      if (lenient.equals("false") || lenient.equals("no")) {
        convertor.setLenient(false);
      } else if (lenient.equals("true") || lenient.equals("yes")) {
        convertor.setLenient(true);
      } else {
        throw new Exception(
            "Invalid value \""
                + lenient
                + "\" for lenient attribute at "
                + DomHelper.getLocation(configElement));
      }
    }

    Element patternsEl =
        DomHelper.getChildElement(configElement, FormsConstants.DEFINITION_NS, "patterns", false);
    if (patternsEl != null) {
      Element patternEl[] =
          DomHelper.getChildElements(patternsEl, FormsConstants.DEFINITION_NS, "pattern");
      for (int i = 0; i < patternEl.length; i++) {
        String locale = patternEl[i].getAttribute("locale");
        String pattern = DomHelper.getElementText(patternEl[i]);
        if (pattern.length() == 0)
          throw new Exception(
              "pattern element does not contain any content at "
                  + DomHelper.getLocation(patternEl[i]));
        if (locale.length() == 0) convertor.setNonLocalizedPattern(pattern);
        else {
          Locale loc = I18nUtils.parseLocale(locale);
          convertor.addFormattingPattern(loc, pattern);
        }
      }
    }

    return convertor;
  }