예제 #1
0
  private void processDescendantCondition(Object sdt, String xpathBase, int index, Tag tag) {

    Condition c = null;

    HashMap<String, String> map = QueryString.parseQueryString(tag.getVal(), true);

    String conditionId = map.get(BINDING_ROLE_CONDITIONAL);

    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));

      Condition newCondition = c.repeat(xpathBase, index, conditions, xPaths);

      // set sdt to use it
      map.put(BINDING_ROLE_CONDITIONAL, newCondition.getId());
      tag.setVal(QueryString.create(map));
    }
  }
예제 #2
0
  private void emptyRepeatTagValue(final Tag tag) {

    final String tagVal = tag.getVal();
    final Pattern stripRepeatArgPattern = Pattern.compile("(.*od:repeat=)([^&]*)(.*)");
    final Matcher stripPatternMatcher = stripRepeatArgPattern.matcher(tagVal);
    if (!stripPatternMatcher.matches()) {
      log.error(
          "Cannot find repeat tag in sdtPr/tag while processing repeat; something is wrong with "
              + tagVal);
      return;
    }
    //		final String emptyRepeatValue = stripPatternMatcher.group(1)
    //				+ stripPatternMatcher.group(3);
    final String emptyRepeatValue =
        BINDING_RESULT_RPTD + "=" + stripPatternMatcher.group(2) + stripPatternMatcher.group(3);
    tag.setVal(emptyRepeatValue);
  }
    @Override
    public void apply(SdtElement element, Object parent, List<Object> siblings) {

      System.out.println();

      SdtPr sdtPr = element.getSdtPr();
      if (sdtPr == null) {
        System.out.println(
            callback.indent
                + element.getClass().getSimpleName()
                + "  [no sdtPr!]"
                + " (having parent "
                + parent.getClass().getSimpleName()
                + ")");
      } else {
        System.out.println(
            callback.indent
                + element.getClass().getSimpleName()
                + " (having parent "
                + parent.getClass().getSimpleName()
                + ")");

        CTDataBinding binding = (CTDataBinding) XmlUtils.unwrap(sdtPr.getDataBinding());
        if (binding != null) {
          System.out.println(callback.indent + "  binding: " + binding.getXpath());
        }

        Tag tag = sdtPr.getTag();
        if (tag == null) return;

        System.out.println(callback.indent + "  " + tag.getVal());

        HashMap<String, String> map = QueryString.parseQueryString(tag.getVal(), true);

        String conditionId = map.get(OpenDoPEHandler.BINDING_ROLE_CONDITIONAL);
        String repeatId = map.get(OpenDoPEHandler.BINDING_ROLE_REPEAT);
        String xp = map.get(OpenDoPEHandler.BINDING_ROLE_XPATH);

        if (conditionId != null) {
          Condition c = ConditionsPart.getConditionById(conditions, conditionId);
          if (c == null) {
            System.out.println(callback.indent + "  " + "Missing condition " + conditionId);
          }

          if (c.getParticle() instanceof org.opendope.conditions.Xpathref) {
            org.opendope.conditions.Xpathref xpathRef = (Xpathref) c.getParticle();
            if (xpathRef == null) {
              System.out.println(
                  callback.indent
                      + "  "
                      + "Condition "
                      + c.getId()
                      + " references a missing xpath!");
            }

            org.opendope.xpaths.Xpaths.Xpath xpath =
                XPathsPart.getXPathById(xPaths, xpathRef.getId());
            if (xpath == null) {
              System.out.println(
                  callback.indent
                      + "  "
                      + "XPath specified in condition '"
                      + c.getId()
                      + "' is missing!");
            } else {
              System.out.println(
                  callback.indent
                      + "  "
                      + xpath.getId()
                      + ": "
                      + xpath.getDataBinding().getXpath());
            }
          } else {
            System.out.println("Complex condition: " + XmlUtils.marshaltoString(c, true, true));
          }

        } else if (repeatId != null) {

          org.opendope.xpaths.Xpaths.Xpath xpath = XPathsPart.getXPathById(xPaths, repeatId);

          if (xpath == null) {
            System.out.println(
                callback.indent
                    + "  "
                    + "XPath specified in repeat '"
                    + repeatId
                    + "' is missing!");
          } else {
            System.out.println(
                callback.indent + "  " + xpath.getId() + ": " + xpath.getDataBinding().getXpath());
          }

        } else if (xp != null) {

          org.opendope.xpaths.Xpaths.Xpath xpath = XPathsPart.getXPathById(xPaths, xp);

          if (xpath == null) {
            System.out.println(
                callback.indent + "  " + "XPath specified with id '" + xp + "' is missing!");
          } else {
            System.out.println(
                callback.indent + "  " + xpath.getId() + ": " + xpath.getDataBinding().getXpath());
          }
        }
      }
    }
예제 #4
0
  /**
   * Insert an empty placeholder SDT, to facilitate round-tripping (ie ability to convert instance
   * docx back to original template), which you may wish to do if you want to insert updated data,
   * but preserve certain manual edits.
   *
   * @param sdt
   * @return
   */
  private List<Object> repeatZero(Object sdt) {

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

    //		if (removeSdtCellsOnFailedCondition) {
    //			// backward compatibility
    //			// NB this is not compatible with reverting functionality, and
    //			// will break if the result is an empty tc
    //			return newContent;
    //		}

    newContent.add(sdt);

    // Change the tag to od:resultRepeatZero
    SdtPr sdtPr = getSdtPr(sdt);

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

    Tag tag = sdtPr.getTag();

    final String tagVal = tag.getVal();
    final Pattern stripRepeatArgPattern = Pattern.compile("(.*od:repeat=)([^&]*)(.*)");
    final Matcher stripPatternMatcher = stripRepeatArgPattern.matcher(tagVal);
    if (!stripPatternMatcher.matches()) {
      log.error(
          "Cannot find repeat tag in sdtPr/tag while processing repeat; something is wrong with "
              + tagVal);
      return newContent;
    }
    final String emptyRepeatValue =
        BINDING_RESULT_RPTD_ZERO
            + "="
            + stripPatternMatcher.group(2)
            + stripPatternMatcher.group(3);
    tag.setVal(emptyRepeatValue);

    // Lock it
    CTLock lock = Context.getWmlObjectFactory().createCTLock();
    lock.setVal(org.docx4j.wml.STLock.SDT_CONTENT_LOCKED);
    JAXBElement<org.docx4j.wml.CTLock> lockWrapped =
        Context.getWmlObjectFactory().createSdtPrLock(lock);
    sdtPr.getRPrOrAliasOrLock().add(lockWrapped); // assumes no lock is there already

    // Empty the content
    // .. OpenDoPEIntegrity fixes this where it is not OK, but
    // where it needs to insert a tc, it has no way of adding original tcPr, so
    // we handle this here
    TcFinder tcFinder = new TcFinder();
    new TraversalUtil(((SdtElement) sdt).getSdtContent().getContent(), tcFinder);
    if (tcFinder.tcList.size() > 0) {
      Tc tc = tcFinder.tcList.get(0);
      tc.getContent().clear();
      P p = Context.getWmlObjectFactory().createP();
      tc.getContent().add(p);
      ((SdtElement) sdt).getSdtContent().getContent().clear();
      ((SdtElement) sdt).getSdtContent().getContent().add(tc);
    } else {
      ((SdtElement) sdt).getSdtContent().getContent().clear();
    }

    return newContent;
  }
예제 #5
0
  private List<Object> processRepeat(
      Object sdt, Map<String, CustomXmlPart> customXmlDataStorageParts, XPathsPart xPathsPart) {

    Tag tag = getSdtPr(sdt).getTag();

    HashMap<String, String> map = QueryString.parseQueryString(tag.getVal(), true);

    String repeatId = map.get(BINDING_ROLE_REPEAT);

    // Check, whether we are in an old repeat case. These can be removed.
    if (StringUtils.isEmpty(repeatId)) return new ArrayList<Object>();

    org.opendope.xpaths.Xpaths.Xpath xpathObj = XPathsPart.getXPathById(xPaths, repeatId);

    String storeItemId = xpathObj.getDataBinding().getStoreItemID();
    String xpath = xpathObj.getDataBinding().getXpath();
    String prefixMappings = xpathObj.getDataBinding().getPrefixMappings();

    // Get the bound XML
    String xpathBase;
    // if (xpath.endsWith("/*")) {
    // xpathBase = xpath.substring(0, xpath.length()-2);
    // } else
    if (xpath.endsWith("/")) {
      xpathBase = xpath.substring(0, xpath.length() - 1);

      // Check, whether the xpath ends with a [1]. If so, guess it comes
      // from a round-tripped path and strip it
    } else if (xpath.endsWith("[1]")) {
      xpathBase = xpath.substring(0, xpath.length() - 3);

    } else {
      xpathBase = xpath;
    }

    // DON'T Drop any trailing position! That breaks nested repeats
    // if (xpathBase.endsWith("]"))
    // xpathBase = xpathBase.substring(0, xpathBase.lastIndexOf("["));

    log.info("/n/n Repeat: using xpath: " + xpathBase);
    List<Node> repeatedSiblings =
        xpathGetNodes(customXmlDataStorageParts, storeItemId, xpathBase, prefixMappings);
    // storeItemId, xpathBase+"/*", prefixMappings);

    // Count siblings
    int numRepeats = repeatedSiblings.size();
    log.debug("yields REPEATS: " + numRepeats);

    if (numRepeats == 0) {
      // return new ArrayList<Object>(); // effectively, delete

      // Change tag to od:resultRepeatZero=id
      return repeatZero(sdt);
    }

    // duplicate content here ...
    List<Object> repeated = cloneRepeatSdt(sdt, xpathBase, numRepeats);

    // deep traverse to fix binding
    DeepTraversor dt = new DeepTraversor();
    dt.xpathBase = xpathBase;
    for (int i = 0; i < repeated.size(); i++) {

      log.info("\n Traversing clone " + i);

      dt.index = i;
      new TraversalUtil(repeated.get(i), dt);
    }
    log.info(".. deep traversals done ");

    // make bookmarks (if any) unique
    for (int i = 0; i < repeated.size(); i++) {
      try {

        // Use the sdt id for uniqueness
        long global = ((SdtElement) repeated.get(i)).getSdtPr().getId().getVal().longValue();

        BookmarkRenumber.fixRange(
            ((SdtElement) repeated.get(i)).getSdtContent().getContent(),
            "CTBookmark",
            "CTMarkupRange",
            null,
            global,
            i);
      } catch (Exception e) {
        // Shouldn't happen .. TODO remove reflection?
        log.error(e.getMessage(), e);
      }
    }

    return repeated;
  }
예제 #6
0
  /**
   * This applies to any sdt which might be a conditional|repeat
   *
   * @param wordMLPackage
   * @param sdtParent
   * @param sdt
   * @param tag
   * @param sdtContent
   * @return
   * @throws Exception
   */
  private List<Object> processBindingRoleIfAny(WordprocessingMLPackage wordMLPackage, Object sdt) {
    log.debug("Processing " + getSdtPr(sdt).getId().getVal());
    Tag tag = getSdtPr(sdt).getTag();

    if (tag == null) {
      List<Object> newContent = new ArrayList<Object>();
      newContent.add(sdt);
      return newContent;
    }

    log.info(tag.getVal());

    HashMap<String, String> map = QueryString.parseQueryString(tag.getVal(), true);

    String conditionId = map.get(BINDING_ROLE_CONDITIONAL);
    String repeatId = map.get(BINDING_ROLE_REPEAT);
    String xp = map.get(BINDING_ROLE_XPATH);
    if (conditionId == null && repeatId == null && xp == null) {
      List<Object> newContent = new ArrayList<Object>();
      newContent.add(sdt);
      return newContent;
    }

    Map<String, CustomXmlPart> customXmlDataStorageParts =
        wordMLPackage.getCustomXmlDataStorageParts();

    if (conditionId != null) {

      log.info("Processing Conditional: " + tag.getVal());

      // At present, this only handles simple conditions
      Condition c = ConditionsPart.getConditionById(conditions, conditionId);
      if (c == null) {
        log.error("Missing condition " + conditionId);
      }

      if (c.evaluate(wordMLPackage, customXmlDataStorageParts, conditions, xPaths)) {
        log.debug("so keeping");

        List<Object> newContent = new ArrayList<Object>();
        newContent.add(sdt);
        return newContent;

      } else {
        return conditionFalse(sdt);
      }

    } else if (repeatId != null) {

      log.info("Processing Repeat: " + tag.getVal());

      return processRepeat(
          sdt, customXmlDataStorageParts, wordMLPackage.getMainDocumentPart().getXPathsPart());

    } else if (xp != null) {

      // Word can't handle an XPath that returns something
      // other than an element
      // eg string or boolean or number, so we'll need to work this out.
      // In principal, we could do this in this pre-processing step,
      // or via bind.xslt.

      // Doing it here means the bind.xslt step can be restricted to pure
      // Word-like processing.

      // Doing it there means we can take advantage of the multiline
      // processing we have there, and less code.
      // So as from 13 Sept 2011 (what will be 2.7.1), do it there.

      List<Object> newContent = new ArrayList<Object>();
      newContent.add(sdt);
      return newContent;
    }
    // shouldn't happen
    return null;
  }
예제 #7
0
  private WordprocessingMLPackage fetchComponents(
      WordprocessingMLPackage srcPackage, ContentAccessor contentAccessor) throws Docx4JException {

    // convert components to altChunk
    Map<Integer, CTAltChunk> replacements = new HashMap<Integer, CTAltChunk>();
    Integer index = 0;
    justGotAComponent = false;

    LinkedList<Integer> continuousBeforeIndex = new LinkedList<Integer>();
    List<Boolean> continuousBefore = new ArrayList<Boolean>();

    List<Boolean> continuousAfter = new ArrayList<Boolean>();

    for (Object block : contentAccessor.getContent()) {

      // Object ublock = XmlUtils.unwrap(block);
      if (block instanceof org.docx4j.wml.SdtBlock) {

        org.docx4j.wml.SdtBlock sdt = (org.docx4j.wml.SdtBlock) block;

        Tag tag = getSdtPr(sdt).getTag();

        if (tag == null) {
          List<Object> newContent = new ArrayList<Object>();
          newContent.add(sdt);
          continue;
        }

        log.info(tag.getVal());

        HashMap<String, String> map = QueryString.parseQueryString(tag.getVal(), true);

        String componentId = map.get(BINDING_ROLE_COMPONENT);
        if (componentId == null) continue;

        // Convert the sdt to a w:altChunk
        // .. get the IRI
        String iri = ComponentsPart.getComponentById(components, componentId).getIri();
        log.debug("Fetching " + iri);

        if (docxFetcher == null) {
          log.error("You need a docxFetcher (and the MergeDocx extension) to fetch components");
          return srcPackage;
        }

        // .. create the part
        AlternativeFormatInputPart afiPart =
            new AlternativeFormatInputPart(
                getNewPartName(
                    "/chunk", ".docx", srcPackage.getMainDocumentPart().getRelationshipsPart()));
        afiPart.setBinaryData(docxFetcher.getDocxFromIRI(iri));

        afiPart.setContentType(
            new ContentType(
                "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml")); // docx

        Relationship altChunkRel = srcPackage.getMainDocumentPart().addTargetPart(afiPart);
        CTAltChunk ac = Context.getWmlObjectFactory().createCTAltChunk();
        ac.setId(altChunkRel.getId());

        replacements.put(index, ac);

        /*
         * 2011 12 11 TODO.  Rethink support for
         * od:continuousBefore and od:continuousAfter.
         */

        // This is handled in this class
        if (map.get(BINDING_ROLE_COMPONENT_BEFORE) != null
            && map.get(BINDING_ROLE_COMPONENT_BEFORE).equals("true")) {
          continuousBefore.add(Boolean.TRUE);
          continuousBeforeIndex.addFirst(index);
          log.info("ctsBefore index: " + index);
        } else {
          continuousBefore.add(Boolean.FALSE);
          continuousBeforeIndex.addFirst(index);
        }

        // The following is handled in ProcessAltChunk
        if (map.get(BINDING_ROLE_COMPONENT_AFTER) != null
            && map.get(BINDING_ROLE_COMPONENT_AFTER).equals("true")) {
          continuousAfter.add(Boolean.TRUE);
        } else {
          continuousAfter.add(Boolean.TRUE);
        }

        justGotAComponent = true;
      }
      index++;
    }

    if (!justGotAComponent) {
      return srcPackage;
    }

    // Now replace in list
    for (Integer key : replacements.keySet()) {
      contentAccessor.getContent().set(key, replacements.get(key));
    }

    // Go through docx in reverse order
    List<Object> bodyChildren = contentAccessor.getContent();
    int i = 0;
    for (Integer indexIntoBody : continuousBeforeIndex) {

      if (continuousBefore.get(i)) {
        // Element before the w:altChunk
        if (indexIntoBody == 0) {
          // // Insert a sectPr right at the beginning of the docx?
          // // TODO check this isn't necessary
          // SectPr newSectPr =
          // Context.getWmlObjectFactory().createSectPr();
          // SectPr.Type type =
          // Context.getWmlObjectFactory().createSectPrType();
          // type.setVal("continuous");
          // newSectPr.setType( type );
          //
          // bodyChildren.add(0, newSectPr);

        } else {
          Object block = bodyChildren.get(indexIntoBody.intValue() - 1);
          if (block instanceof P
              && ((P) block).getPPr() != null
              && ((P) block).getPPr().getSectPr() != null) {
            makeContinuous(((P) block).getPPr().getSectPr());
          } else if (block instanceof P) {
            // More likely
            PPr ppr = ((P) block).getPPr();
            if (ppr == null) {
              ppr = Context.getWmlObjectFactory().createPPr();
              ((P) block).setPPr(ppr);
            }
            SectPr newSectPr = Context.getWmlObjectFactory().createSectPr();
            SectPr.Type type = Context.getWmlObjectFactory().createSectPrType();
            type.setVal("continuous");
            newSectPr.setType(type);

            ppr.setSectPr(newSectPr);
          } else {
            // Equally likely - its a table or something, so add a p
            P newP = Context.getWmlObjectFactory().createP();
            PPr ppr = Context.getWmlObjectFactory().createPPr();
            newP.setPPr(ppr);

            SectPr newSectPr = Context.getWmlObjectFactory().createSectPr();
            SectPr.Type type = Context.getWmlObjectFactory().createSectPrType();
            type.setVal("continuous");
            newSectPr.setType(type);
            ppr.setSectPr(newSectPr);

            bodyChildren.add(indexIntoBody.intValue(), newP); // add
            // before
            // altChunk
          }
        }
      }
      // else nothing specified, so go with normal MergeDocx behaviour

      i++;
    }

    // process altChunk
    try {
      // Use reflection, so docx4j can be built
      // by users who don't have the MergeDocx utility
      Class<?> documentBuilder = Class.forName("com.plutext.merge.ProcessAltChunk");
      // Method method = documentBuilder.getMethod("merge",
      // wmlPkgList.getClass());
      Method[] methods = documentBuilder.getMethods();
      Method processMethod = null;
      for (int j = 0; j < methods.length; j++) {
        log.debug(methods[j].getName());
        if (methods[j].getName().equals("process")) {
          processMethod = methods[j];
        }
      }
      if (processMethod == null) throw new NoSuchMethodException();
      return (WordprocessingMLPackage) processMethod.invoke(null, srcPackage);

    } catch (ClassNotFoundException e) {
      extensionMissing(e);
      justGotAComponent = false;
      return srcPackage;
      // throw new Docx4JException("Problem processing w:altChunk", e);
    } catch (NoSuchMethodException e) {
      // Degrade gracefully
      extensionMissing(e);
      justGotAComponent = false;
      return srcPackage;
      // throw new Docx4JException("Problem processing w:altChunk", e);
    } catch (Exception e) {
      throw new Docx4JException("Problem processing w:altChunk", e);
    }
  }
예제 #8
0
  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));
    }
  }