private org.docx4j.vml.CTTextbox getTextBox(org.docx4j.wml.Pict pict) {

    org.docx4j.vml.CTShape shape = null;
    for (Object o2 : pict.getAnyAndAny()) {

      o2 = XmlUtils.unwrap(o2);
      //			System.out.println(o.getClass().getName());
      if (o2 instanceof org.docx4j.vml.CTShape) {
        shape = (org.docx4j.vml.CTShape) o2;
        break;
      }
    }
    if (shape == null) {
      getLog().warn("no shape in pict ");
      return null;
    } else {

      org.docx4j.vml.CTTextbox textBox = null;
      org.docx4j.vml.wordprocessingDrawing.CTWrap w10Wrap = null;
      for (Object o2 : shape.getPathOrFormulasOrHandles()) {

        o2 = XmlUtils.unwrap(o2);

        if (o2 instanceof org.docx4j.vml.CTTextbox) {
          textBox = (org.docx4j.vml.CTTextbox) o2;
        }
        if (o2 instanceof org.docx4j.vml.wordprocessingDrawing.CTWrap) {
          w10Wrap = (org.docx4j.vml.wordprocessingDrawing.CTWrap) o2;
        }
      }

      return textBox;
    }
  }
Beispiel #2
0
  /** Example of how to find an object in document.xml via traversal (as opposed to XPath) */
  public static void main(String[] args) throws Exception {

    String inputfilepath = System.getProperty("user.dir") + "/checkbox.docx";

    WordprocessingMLPackage wordMLPackage =
        WordprocessingMLPackage.load(new java.io.File(inputfilepath));
    MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart();

    Finder finder = new Finder(FldChar.class); // <----- change this to suit
    new TraversalUtil(documentPart.getContent(), finder);

    System.out.println("got " + finder.results.size() + " of type " + finder.typeToFind.getName());

    for (Object o : finder.results) {

      Object o2 = XmlUtils.unwrap(o);
      // this is ok, provided the results of the Callback
      // won't be marshalled

      if (o2 instanceof org.docx4j.wml.Text) {

        org.docx4j.wml.Text txt = (org.docx4j.wml.Text) o2;

        System.out.println(txt.getValue());

      } else {
        System.out.println(XmlUtils.marshaltoString(o, true, true));
      }
    }
  }
    @Override
    public void walkJAXBElements(Object parent) {
      // Breadth first

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

      Object parentUnwrapped = XmlUtils.unwrap(parent);
      List<Object> children = getChildren(parentUnwrapped);
      if (children == null) {
        log.debug("no children: " + parentUnwrapped.getClass().getName());
        return;
      } else {
        for (Object o : children) {
          newChildren.addAll(this.apply(o));
        }
      }
      // Replace list, so we'll traverse all the new sdts we've just
      // created
      TraversalUtil.replaceChildren(parentUnwrapped, newChildren);

      children = getChildren(parentUnwrapped);
      if (children == null) {
        log.debug("no children: " + parentUnwrapped.getClass().getName());
      } else {
        for (Object o : children) {

          // *** this.apply(o);

          if (this.shouldTraverse(o)) {
            walkJAXBElements(o);
          }
        }
      }
    }
    @Override
    public List<Object> apply(Object wrapped) throws RuntimeException {

      // apply processSdt to any sdt
      // which might be a conditional|repeat
      Object o = XmlUtils.unwrap(wrapped);
      if (o instanceof org.docx4j.wml.SdtBlock
          || o instanceof org.docx4j.wml.SdtRun
          || o instanceof org.docx4j.wml.CTSdtRow
          || o instanceof org.docx4j.wml.CTSdtCell) {

        if (getSdtPr(o).getDataBinding() == null) {
          // a real binding attribute trumps any tag
          return processBindingRoleIfAny(wordMLPackage, o);
        }

      } else {
        // log.warn("TODO: Handle " + o.getClass().getName() +
        // " (if that's an sdt)");
      }

      // Otherwise just preserve the content
      List<Object> newContent = new ArrayList<Object>();

      newContent.add(wrapped); // we want the JAXBElement (if any)
      return newContent;
    }
  /**
   * Use an XSLT to alter the contents of this package. The output of the transformation must be
   * valid pck:package/pck:part format, as emitted by Word 2007.
   *
   * @param is
   * @param transformParameters
   * @throws Exception
   */
  public void transform(Templates xslt, Map<String, Object> transformParameters) throws Exception {

    // Prepare in the input document

    FlatOpcXmlCreator worker = new FlatOpcXmlCreator(this);
    org.docx4j.xmlPackage.Package pkg = worker.get();

    JAXBContext jc = Context.jcXmlPackage;
    Marshaller marshaller = jc.createMarshaller();
    org.w3c.dom.Document doc = org.docx4j.XmlUtils.neww3cDomDocument();
    marshaller.marshal(pkg, doc);

    //		javax.xml.bind.util.JAXBResult result = new javax.xml.bind.util.JAXBResult(jc );

    // Use constructor which takes Unmarshaller, rather than JAXBContext,
    // so we can set JaxbValidationEventHandler
    Unmarshaller u = jc.createUnmarshaller();
    u.setEventHandler(new org.docx4j.jaxb.JaxbValidationEventHandler());
    javax.xml.bind.util.JAXBResult result = new javax.xml.bind.util.JAXBResult(u);

    // Perform the transformation
    org.docx4j.XmlUtils.transform(doc, xslt, transformParameters, result);

    //		javax.xml.bind.JAXBElement je = (javax.xml.bind.JAXBElement)result.getResult();
    //		org.docx4j.xmlPackage.Package wmlPackageEl = (org.docx4j.xmlPackage.Package)je.getValue();
    org.docx4j.xmlPackage.Package wmlPackageEl =
        (org.docx4j.xmlPackage.Package) XmlUtils.unwrap(result.getResult());

    org.docx4j.convert.in.FlatOpcXmlImporter xmlPackage =
        new org.docx4j.convert.in.FlatOpcXmlImporter(wmlPackageEl);

    ContentTypeManager ctm = new ContentTypeManager();

    Part tmpDocPart = xmlPackage.getRawPart(ctm, "/word/document.xml", null);
    Part tmpStylesPart = xmlPackage.getRawPart(ctm, "/word/styles.xml", null);

    // This code assumes all the existing rels etc of
    // the existing main document part are still relevant.
    //		if (wmlDocument==null) {
    //			log.warn("Couldn't get main document part from package transform result!");
    //		} else {
    //			this.getMainDocumentPart().setJaxbElement(wmlDocument);
    //		}
    this.getMainDocumentPart()
        .setJaxbElement(((JaxbXmlPart<Document>) tmpDocPart).getJaxbElement());
    //
    //		if (wmlStyles==null) {
    //			log.warn("Couldn't get style definitions part from package transform result!");
    //		} else {
    //			this.getMainDocumentPart().getStyleDefinitionsPart().setJaxbElement(wmlStyles);
    //		}
    this.getMainDocumentPart()
        .getStyleDefinitionsPart(true)
        .setJaxbElement(((JaxbXmlPart<Styles>) tmpStylesPart).getJaxbElement());
  }
    @Override
    public void walkJAXBElements(Object parent) {

      List<Object> children = getChildren(parent);
      if (children != null) {

        for (Object o : children) {

          o = XmlUtils.unwrap(o);
          this.apply(o);

          if (this.shouldTraverse(o)) {
            walkJAXBElements(o);
          }
        }
      }
    }
    @Override
    public void walkJAXBElements(Object parent) {

      List children = getChildren(parent);
      if (children != null) {
        String oldIndent = indent;
        indent += "  ";
        for (Object o : children) {
          // if its wrapped in javax.xml.bind.JAXBElement, get its
          // value; this is ok, provided the results of the Callback
          // won't be marshalled
          o = XmlUtils.unwrap(o);
          this.apply(o, parent, children);
          if (this.shouldTraverse(o)) {
            walkJAXBElements(o);
          }
        }
        indent = oldIndent;
      }
    }
    @Override
    public void walkJAXBElements(Object parent) {

      List children = getChildren(parent);
      if (children != null) {

        for (Object o : children) {

          // if its wrapped in javax.xml.bind.JAXBElement, get its
          // value; this is ok, provided the results of the Callback
          // won't be marshalled
          o = XmlUtils.unwrap(o);

          // workaround for broken getParent (since 3.0.0)
          if (o instanceof Child) {
            if (parent instanceof SdtBlock) {
              ((Child) o).setParent(((SdtBlock) parent).getSdtContent().getContent());
              // Is that the right semantics for parent object?
              // TODO: other corrections
            } else {
              ((Child) o).setParent(parent);
            }
          }

          this.apply(o);

          if (o instanceof SdtBlock) {
            ll.addLast((SdtBlock) o);
          }

          if (this.shouldTraverse(o)) {
            walkJAXBElements(o);
          }

          if (o instanceof SdtBlock) {
            ll.removeLast();
          }
        }
      }
    }
  @Override // so we can manage the stack
  public void walkJAXBElements(Object parent) {

    if (parent instanceof P) {
      pStack.push((P) parent);
    }

    // Same as superclass:
    List children = getChildren(parent);
    if (children != null) {

      for (Object o : children) {

        // if its wrapped in javax.xml.bind.JAXBElement, get its
        // value; this is ok, provided the results of the Callback
        // won't be marshalled
        o = XmlUtils.unwrap(o);

        // workaround for broken getParent (since 3.0.0)
        if (o instanceof Child) {
          if (parent instanceof SdtBlock) {
            ((Child) o).setParent(((SdtBlock) parent).getSdtContent());
          } else {
            ((Child) o).setParent(parent);
          }
        }

        this.apply(o);

        if (this.shouldTraverse(o)) {
          walkJAXBElements(o);
        }
      }
    }

    if (parent instanceof P) {
      pStack.pop();
    }
  }
Beispiel #10
0
  /**
   * Get a Part (except a relationships part), but not its relationships part or related parts.
   * Useful if you need quick access to just this part. This can be called directly from outside the
   * library, in which case the Part will not be owned by a Package until the calling code makes it
   * so.
   *
   * @see To get a Part and all its related parts, and add all to a package, use getPart.
   * @param partByteArrays
   * @param ctm
   * @param resolvedPartUri
   * @param rel
   * @return
   * @throws Docx4JException including if result is null
   */
  public Part getRawPart(ContentTypeManager ctm, String resolvedPartUri, Relationship rel)
      throws Docx4JException {

    Part part = null;

    InputStream is = null;
    try {
      try {
        log.debug("resolved uri: " + resolvedPartUri);

        // Get a subclass of Part appropriate for this content type
        // This will throw UnrecognisedPartException in the absence of
        // specific knowledge. Hence it is important to get the is
        // first, as we do above.
        part = ctm.getPart("/" + resolvedPartUri, rel);

        log.info("ctm returned " + part.getClass().getName());

        if (part instanceof org.docx4j.openpackaging.parts.ThemePart
            || part instanceof org.docx4j.openpackaging.parts.DocPropsCorePart
            || part instanceof org.docx4j.openpackaging.parts.DocPropsCustomPart
            || part instanceof org.docx4j.openpackaging.parts.DocPropsExtendedPart
            || part instanceof org.docx4j.openpackaging.parts.CustomXmlDataStoragePropertiesPart
            || part instanceof org.docx4j.openpackaging.parts.digitalsignature.XmlSignaturePart
            || part instanceof org.docx4j.openpackaging.parts.JaxbXmlPart) {

          // Nothing to do here

        } else if (part instanceof org.docx4j.openpackaging.parts.WordprocessingML.BinaryPart) {

          log.debug("Detected BinaryPart " + part.getClass().getName());
          //					is = partStore.loadPart( resolvedPartUri);
          //					((BinaryPart)part).setBinaryData(is);

        } else if (part instanceof org.docx4j.openpackaging.parts.CustomXmlDataStoragePart) {
          // ContentTypeManager initially detects them as CustomXmlDataStoragePart;
          // the below changes as necessary

          // Is it a part we know?
          is = partStore.loadPart(resolvedPartUri);
          try {
            Unmarshaller u = Context.jc.createUnmarshaller();
            Object o = u.unmarshal(is);
            log.debug(o.getClass().getName());

            PartName name = part.getPartName();
            if (o instanceof CoverPageProperties) {

              part = new DocPropsCoverPagePart(name);
              ((DocPropsCoverPagePart) part).setJaxbElement((CoverPageProperties) o);

            } else if (o instanceof org.opendope.conditions.Conditions) {

              part = new ConditionsPart(name);
              ((ConditionsPart) part).setJaxbElement((org.opendope.conditions.Conditions) o);

            } else if (o instanceof org.opendope.xpaths.Xpaths) {

              part = new XPathsPart(name);
              ((XPathsPart) part).setJaxbElement((org.opendope.xpaths.Xpaths) o);

            } else if (o instanceof org.opendope.questions.Questionnaire) {

              part = new QuestionsPart(name);
              ((QuestionsPart) part).setJaxbElement((org.opendope.questions.Questionnaire) o);

            } else if (o instanceof org.opendope.answers.Answers) {

              part = new StandardisedAnswersPart(name);
              ((StandardisedAnswersPart) part).setJaxbElement((org.opendope.answers.Answers) o);

            } else if (o instanceof org.opendope.components.Components) {

              part = new ComponentsPart(name);
              ((ComponentsPart) part).setJaxbElement((org.opendope.components.Components) o);

            } else if (o instanceof JAXBElement<?>
                && XmlUtils.unwrap(o) instanceof org.docx4j.bibliography.CTSources) {
              part = new BibliographyPart(name);
              ((BibliographyPart) part)
                  .setJaxbElement((JAXBElement<org.docx4j.bibliography.CTSources>) o);

            } else {

              log.error("TODO: handle known CustomXmlPart part  " + o.getClass().getName());

              CustomXmlDataStorage data = getCustomXmlDataStorageClass().factory();
              is.reset();
              data.setDocument(is); // Not necessarily JAXB, that's just our method name
              ((org.docx4j.openpackaging.parts.CustomXmlDataStoragePart) part).setData(data);
            }

          } catch (javax.xml.bind.UnmarshalException ue) {

            log.warn("No JAXB model for this CustomXmlDataStorage part; " + ue.getMessage());

            CustomXmlDataStorage data = getCustomXmlDataStorageClass().factory();
            is.reset();
            data.setDocument(is); // Not necessarily JAXB, that's just our method name
            ((org.docx4j.openpackaging.parts.CustomXmlDataStoragePart) part).setData(data);
          }

        } else if (part instanceof org.docx4j.openpackaging.parts.XmlPart) {

          is = partStore.loadPart(resolvedPartUri);

          //					try {
          ((XmlPart) part).setDocument(is);

          // Experimental 22/6/2011; don't fall back to binary (which we used to)

          //					} catch (Docx4JException d) {
          //						// This isn't an XML part after all,
          //						// even though ContentTypeManager detected it as such
          //						// So get it as a binary part
          //						part = getBinaryPart(partByteArrays, ctm, resolvedPartUri);
          //						log.warn("Could not parse as XML, so using BinaryPart for "
          //								+ resolvedPartUri);
          //						((BinaryPart)part).setBinaryData(is);
          //					}

        } else {
          // Shouldn't happen, since ContentTypeManagerImpl should
          // return an instance of one of the above, or throw an
          // Exception.

          log.error("No suitable part found for: " + resolvedPartUri);
          part = null;
        }

      } catch (PartUnrecognisedException e) {
        log.error("PartUnrecognisedException shouldn't happen anymore!", e);
        // Try to get it as a binary part
        part = getBinaryPart(ctm, resolvedPartUri);
        log.warn("Using BinaryPart for " + resolvedPartUri);

        //				is = partStore.loadPart( resolvedPartUri);
        //				((BinaryPart)part).setBinaryData(is);
      }
    } catch (Exception ex) {
      // IOException, URISyntaxException
      ex.printStackTrace();
      throw new Docx4JException("Failed to getPart", ex);

    } finally {
      IOUtils.closeQuietly(is);
    }

    if (part == null) {
      throw new Docx4JException(
          "cannot find part "
              + resolvedPartUri
              + " from rel "
              + rel.getId()
              + "="
              + rel.getTarget());
    }

    return part;
  }
Beispiel #11
0
  /**
   * Get a Part (except a relationships part), but not its relationships part or related parts.
   * Useful if you need quick access to just this part. This can be called directly from outside the
   * library, in which case the Part will not be owned by a Package until the calling code makes it
   * so.
   *
   * @see To get a Part and all its related parts, and add all to a package, use getPart.
   * @param zf
   * @param resolvedPartUri
   * @return
   * @throws URISyntaxException
   * @throws InvalidFormatException
   */
  public static Part getRawPart(
      ZipFile zf, ContentTypeManager ctm, String resolvedPartUri, Relationship rel)
      throws Docx4JException {
    Part part = null;

    InputStream is = null;
    try {
      try {
        log.debug("resolved uri: " + resolvedPartUri);
        is = getInputStreamFromZippedPart(zf, resolvedPartUri);

        // Get a subclass of Part appropriate for this content type
        // This will throw UnrecognisedPartException in the absence of
        // specific knowledge. Hence it is important to get the is
        // first, as we do above.
        part = ctm.getPart("/" + resolvedPartUri, rel);

        if (part instanceof org.docx4j.openpackaging.parts.ThemePart) {

          ((org.docx4j.openpackaging.parts.JaxbXmlPart) part).setJAXBContext(Context.jcThemePart);
          ((org.docx4j.openpackaging.parts.JaxbXmlPart) part).unmarshal(is);

        } else if (part instanceof org.docx4j.openpackaging.parts.DocPropsCorePart) {

          ((org.docx4j.openpackaging.parts.JaxbXmlPart) part)
              .setJAXBContext(Context.jcDocPropsCore);
          ((org.docx4j.openpackaging.parts.JaxbXmlPart) part).unmarshal(is);

        } else if (part instanceof org.docx4j.openpackaging.parts.DocPropsCustomPart) {

          ((org.docx4j.openpackaging.parts.JaxbXmlPart) part)
              .setJAXBContext(Context.jcDocPropsCustom);
          ((org.docx4j.openpackaging.parts.JaxbXmlPart) part).unmarshal(is);

        } else if (part instanceof org.docx4j.openpackaging.parts.DocPropsExtendedPart) {

          ((org.docx4j.openpackaging.parts.JaxbXmlPart) part)
              .setJAXBContext(Context.jcDocPropsExtended);
          ((org.docx4j.openpackaging.parts.JaxbXmlPart) part).unmarshal(is);

        } else if (part
            instanceof org.docx4j.openpackaging.parts.CustomXmlDataStoragePropertiesPart) {

          ((org.docx4j.openpackaging.parts.JaxbXmlPart) part)
              .setJAXBContext(Context.jcCustomXmlProperties);
          ((org.docx4j.openpackaging.parts.JaxbXmlPart) part).unmarshal(is);

        } else if (part
            instanceof org.docx4j.openpackaging.parts.digitalsignature.XmlSignaturePart) {

          ((org.docx4j.openpackaging.parts.JaxbXmlPart) part).setJAXBContext(Context.jcXmlDSig);
          ((org.docx4j.openpackaging.parts.JaxbXmlPart) part).unmarshal(is);

        } else if (part instanceof org.docx4j.openpackaging.parts.JaxbXmlPart) {

          // MainDocument part, Styles part, Font part etc

          ((org.docx4j.openpackaging.parts.JaxbXmlPart) part).setJAXBContext(Context.jc);
          ((org.docx4j.openpackaging.parts.JaxbXmlPart) part).unmarshal(is);

        } else if (part instanceof org.docx4j.openpackaging.parts.WordprocessingML.BinaryPart) {

          log.debug("Detected BinaryPart " + part.getClass().getName());
          if (conserveMemory) {
            ((BinaryPart) part).setBinaryDataRef(zf.getName(), resolvedPartUri);
          } else {
            ((BinaryPart) part).setBinaryData(is);
          }

        } else if (part instanceof org.docx4j.openpackaging.parts.CustomXmlDataStoragePart) {

          // Is it a part we know?
          try {
            Unmarshaller u = Context.jc.createUnmarshaller();
            Object o = u.unmarshal(is);
            log.debug(o.getClass().getName());

            PartName name = part.getPartName();

            if (o instanceof org.opendope.conditions.Conditions) {

              part = new ConditionsPart(name);
              ((ConditionsPart) part).setJaxbElement((org.opendope.conditions.Conditions) o);

            } else if (o instanceof org.opendope.xpaths.Xpaths) {

              part = new XPathsPart(name);
              ((XPathsPart) part).setJaxbElement((org.opendope.xpaths.Xpaths) o);

            } else if (o instanceof org.opendope.questions.Questionnaire) {

              part = new QuestionsPart(name);
              ((QuestionsPart) part).setJaxbElement((org.opendope.questions.Questionnaire) o);

            } else if (o instanceof org.opendope.answers.Answers) {

              part = new StandardisedAnswersPart(name);
              ((StandardisedAnswersPart) part).setJaxbElement((org.opendope.answers.Answers) o);

            } else if (o instanceof org.opendope.components.Components) {

              part = new ComponentsPart(name);
              ((ComponentsPart) part).setJaxbElement((org.opendope.components.Components) o);

            } else if (o instanceof JAXBElement<?>
                && XmlUtils.unwrap(o) instanceof org.docx4j.bibliography.CTSources) {
              part = new BibliographyPart(name);
              ((BibliographyPart) part)
                  .setJaxbElement((JAXBElement<org.docx4j.bibliography.CTSources>) o);

            } else {

              log.warn("No known part after all for CustomXmlPart " + o.getClass().getName());

              CustomXmlDataStorage data = getCustomXmlDataStorageClass().factory();
              is.reset();
              data.setDocument(is); // Not necessarily JAXB, that's just our method name
              ((org.docx4j.openpackaging.parts.CustomXmlDataStoragePart) part).setData(data);
            }

          } catch (javax.xml.bind.UnmarshalException ue) {

            // No ...
            CustomXmlDataStorage data = getCustomXmlDataStorageClass().factory();
            is.reset();
            data.setDocument(is); // Not necessarily JAXB, that's just our method name
            ((org.docx4j.openpackaging.parts.CustomXmlDataStoragePart) part).setData(data);
          }

        } else if (part instanceof org.docx4j.openpackaging.parts.XmlPart) {

          try {
            ((XmlPart) part).setDocument(is);
          } catch (Docx4JException d) {
            // This isn't an XML part after all,
            // even though ContentTypeManager detected it as such
            // So get it as a binary part
            part = getBinaryPart(zf, ctm, resolvedPartUri);
            if (conserveMemory) {
              ((BinaryPart) part).setBinaryDataRef(zf.getName(), resolvedPartUri);
            } else {
              ((BinaryPart) part).setBinaryData(is);
            }
          }

        } else {
          // Shouldn't happen, since ContentTypeManagerImpl should
          // return an instance of one of the above, or throw an
          // Exception.

          log.error("No suitable part found for: " + resolvedPartUri);
          part = null;
        }

      } catch (PartUnrecognisedException e) {
        log.warn("PartUnrecognisedException shouldn't happen anymore!");
        // Try to get it as a binary part
        part = getBinaryPart(zf, ctm, resolvedPartUri);
        if (conserveMemory) {
          ((BinaryPart) part).setBinaryDataRef(zf.getName(), resolvedPartUri);
        } else {
          ((BinaryPart) part).setBinaryData(is);
        }
      }
    } catch (Exception ex) {
      // IOException, URISyntaxException
      ex.printStackTrace();
      throw new Docx4JException("Failed to getPart", ex);

    } finally {
      if (is != null) {
        try {
          is.close();
        } catch (IOException exc) {
          exc.printStackTrace();
        }
      }
    }
    return part;
  }
    @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());
          }
        }
      }
    }
  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));
    }
  }