private List<Object> cloneRepeatSdt(Object sdt, String xpathBase, int numRepeats) {

    List<Object> newContent = new ArrayList<Object>();

    SdtPr sdtPr = getSdtPr(sdt);

    log.debug(XmlUtils.marshaltoString(sdtPr, true, true));

    // CTDataBinding binding =
    // (CTDataBinding)XmlUtils.unwrap(sdtPr.getDataBinding());
    CTDataBinding binding = sdtPr.getDataBinding();
    if (binding != null) { // Shouldn't be a binding anyway
      sdtPr.getRPrOrAliasOrLock().remove(binding);
    }

    emptyRepeatTagValue(sdtPr.getTag()); // 2012 07 15: do it to the first one

    for (int i = 0; i < numRepeats; i++) {

      // 2012 07 13: for "od:RptPosCon" processing to
      // work (conditional inclusion dependant on position
      // in repeat), we need each entry (ie including the
      // original) to have the same tag (which I've changed
      // to od:rptd).

      if (i > 0) {
        // Change ID
        sdtPr.setId();
      } // preserve ID on index 0, important for OpenDoPEReverter!

      // Clone
      newContent.add(XmlUtils.deepCopy(sdt));
    }

    return newContent;
  }
  private void processDescendantBindings(Object sdt, String xpathBase, int index) {

    SdtPr sdtPr = getSdtPr(sdt);

    // log.debug(XmlUtils.marshaltoString(sdtPr, true, true));

    // Give it a unique ID (supersedes above?)
    sdtPr.setId();

    // log.debug(XmlUtils.marshaltoString(sdtPr, true, true));
    CTDataBinding binding = (CTDataBinding) XmlUtils.unwrap(sdtPr.getDataBinding());

    String thisXPath = null;

    // It'll have one of these three...
    String conditionId = null;
    String repeatId = null;
    String bindingId = null;

    org.opendope.xpaths.Xpaths.Xpath xpathObj = null;

    Tag tag = sdtPr.getTag();
    if (tag == null) return;
    HashMap<String, String> map = QueryString.parseQueryString(tag.getVal(), true);

    if (binding == null) {

      conditionId = map.get(BINDING_ROLE_CONDITIONAL);
      repeatId = map.get(BINDING_ROLE_REPEAT);

      if (conditionId != null) {

        //				c = ConditionsPart.getConditionById(conditions, conditionId);
        //				if (c == null) {
        //					log.error("Missing condition " + conditionId);
        //					throw new InputIntegrityException("Required condition '" + conditionId + "' is
        // missing");
        //				}
        //
        //				// TODO: this code assumes the condition contains
        //				// a simple xpath
        //				log.debug("Using condition"
        //						+ XmlUtils.marshaltoString(c, true, true));
        //				xpathObj = getXPathFromCondition(c);
        //				thisXPath = xpathObj.getDataBinding().getXpath();

        processDescendantCondition(sdt, xpathBase, index, tag);
        return;

      } else if (repeatId != null) {

        xpathObj = XPathsPart.getXPathById(xPaths, repeatId);
        thisXPath = xpathObj.getDataBinding().getXpath();

      } else if (map.containsKey(BINDING_CONTENTTYPE)
          || map.containsKey(BINDING_HANDLER)
          || map.containsKey(BINDING_PROGID)) {

        xpathObj = XPathsPart.getXPathById(xPaths, map.get(BINDING_ROLE_XPATH));
        thisXPath = xpathObj.getDataBinding().getXpath();

      } else {

        log.warn("couldn't find binding or bindingrole!");
        // not all sdt's need have a binding;
        // they could be present in the docx for other purposes
        return;

        // NB an OpenDoPE xpath tag (with no w:binding element)
        // eg as created by authoring tool for a "count(" XPath
        // ends up here.
      }

    } else {
      thisXPath = binding.getXpath();

      // Set this stuff up now
      bindingId = map.get(BINDING_ROLE_XPATH);
      xpathObj = XPathsPart.getXPathById(xPaths, bindingId);

      // Sanity test
      if (!thisXPath.equals(xpathObj.getDataBinding().getXpath())) {
        log.error(
            "XPaths didn't match for id "
                + bindingId
                + ": \n\r    "
                + thisXPath
                + "\n\rcf. "
                + xpathObj.getDataBinding().getXpath());
      }

      // 2012 09 20 - when did this break?
      // thisXPath = xpathObj.getDataBinding().getXpath();
    }

    //		System.out.println("xpathBase: " + xpathBase);
    //		System.out.println("index: " + index);
    //		System.out.println("thisXPath: " + thisXPath);

    final String newPath = enhanceXPath(xpathBase, index + 1, thisXPath);

    //		System.out.println("newPath: " + newPath);

    if (log.isDebugEnabled() && !thisXPath.equals(newPath)) {
      log.debug("xpath prefix enhanced " + thisXPath + " to " + newPath);
    }

    if (binding == null) {

      if (repeatId != null) {

        // Create the new xpath object
        org.opendope.xpaths.Xpaths.Xpath newXPathObj =
            createNewXPathObject(newPath, xpathObj, index);

        // set sdt to use it
        map.put(BINDING_ROLE_REPEAT, newXPathObj.getId());
        tag.setVal(QueryString.create(map));

      } else if (map.containsKey(BINDING_CONTENTTYPE)
          || map.containsKey(BINDING_HANDLER)
          || map.containsKey(BINDING_PROGID)) {

        // Also need to create new xpath id, and add that
        org.opendope.xpaths.Xpaths.Xpath newXPathObj =
            createNewXPathObject(newPath, xpathObj, index);

        // set sdt to use it
        map.put(BINDING_ROLE_XPATH, newXPathObj.getId());
        tag.setVal(QueryString.create(map));
      }

    } else {
      binding.setXpath(newPath);

      // Also need to create new xpath id, and add that
      org.opendope.xpaths.Xpaths.Xpath newXPathObj = createNewXPathObject(newPath, xpathObj, index);

      // set sdt to use it
      map.put(BINDING_ROLE_XPATH, newXPathObj.getId());
      tag.setVal(QueryString.create(map));
    }
  }