@Override
  public String characters(final String data, final StartElement element)
      throws IntegritySystemException {
    final String curPath = parser.getCurPath();
    final String theName = element.getLocalName();

    // organizational-unit
    if (curPath.equals(DC_PATH + '/' + Elements.ELEMENT_DC_TITLE)) {
      if (data.length() == 0) {
        properties.put(Elements.ELEMENT_DC_TITLE, "");
        properties.put(TripleStoreUtility.PROP_DC_TITLE, "");
      } else {
        // propertiesMap.put(theName, data);
        properties.put(Elements.ELEMENT_DC_TITLE, data);
        properties.put(TripleStoreUtility.PROP_DC_TITLE, data);
      }
    } else if (theName.equals(Elements.ELEMENT_DESCRIPTION)) {

      if (data.length() == 0) {

        properties.put(Elements.ELEMENT_DESCRIPTION, "");
        properties.put(TripleStoreUtility.PROP_DC_DESCRIPTION, "");
      } else {
        // propertiesMap.put(theName, data);
        properties.put(Elements.ELEMENT_DESCRIPTION, data);
        properties.put(TripleStoreUtility.PROP_DC_DESCRIPTION, data);
      }
    }
    return data;
  }
  /**
   * Handle the start of an element.
   *
   * @param element The element.
   * @return The element.
   * @throws MissingAttributeValueException If a required element is not set.
   * @throws InvalidContentException If the parsed XML contains not allowed parts.
   * @throws WebserverSystemException If the eSciDoc configuration file can not be read. FIXME
   *     should probably not be thrown so late.
   */
  @Override
  public StartElement startElement(final StartElement element)
      throws MissingAttributeValueException, InvalidContentException, WebserverSystemException {

    final String currentPath = parser.getCurPath();
    if (currentPath.equals(this.metadataXPath)) {
      if (LOGGER.isDebugEnabled()) {
        LOGGER.debug("Parser reached " + this.metadataXPath);
      }
      this.curMdRecordDefinition = new MdRecordDefinitionCreate();

      try {
        curMdRecordDefinition.setName(element.getAttributeValue(null, "name"));
      } catch (final NoSuchAttributeException e) {
        throw new InvalidContentException("Attribute name required for md-record-definition.", e);
      }
    } else if (currentPath.equals(this.metadataXPath + "/schema")) {

      try {
        curMdRecordDefinition.setSchemaHref(
            element.getAttributeValue(Constants.XLINK_NS_URI, "href"));
      } catch (final MalformedURLException e) {
        throw new InvalidContentException(e);
      } catch (final IOException e) {
        throw new WebserverSystemException("Configuration could not be read.", e);
      } catch (final NoSuchAttributeException e) {
        throw new InvalidContentException("No href for schema element.", e);
      }
    }

    return element;
  }
  public StartElement startElement(StartElement element) {

    String currentPath = parser.getCurPath();

    if (itemPath.equals(currentPath) || containerPath.equals(currentPath)) {
      membersCount++;
    }
    return element;
  }
  @Override
  public EndElement endElement(final EndElement element) {

    final String currentPath = parser.getCurPath();
    if (currentPath.equals(this.metadataXPath)) {

      this.mdRecordDefinitions.add(this.curMdRecordDefinition);
    }

    return element;
  }
  /**
   * Parser hits an XML character element. Write all elements and all attributes with path to
   * element and value (eg /properties/version/status=released) in a list. If attribute is
   * xlink:href, extract objectId out of href and replace attribute-name in path with /id.
   *
   * @param s XML character element.
   * @param element StAX StartElement
   * @return XML character element.
   */
  @Override
  public String characters(final String s, final StartElement element)
      throws UnsupportedEncodingException {

    String path = parser.getCurPath().replaceFirst("/.*?/", "/");
    if (path.equals(parser.getCurPath())) {
      path = "";
      values.add("\"type\"=\"" + parser.getCurPath().substring(1) + "\"");
    } else {
      if (s != null && !s.trim().equals("")) {
        values.add("\"" + path + "\"=\"" + s + "\"");
      }
    }
    List<Attribute> attributes = element.getAttributes();
    for (Attribute attribute : attributes) {
      if (attribute.getValue() != null && !attribute.getValue().trim().equals("")) {
        String value = attribute.getValue();
        String namespace = attribute.getNamespace();
        String localName = attribute.getLocalName();
        if (namespace != null && Constants.NS_EXTERNAL_XLINK.equals(namespace)) {
          if (attribute.getLocalName().equals("href")) {
            localName = "id";
            value = value.replaceFirst(".*/", "");
            if (path.equals("")) {
              value = value.replaceFirst("(.*?:.*?):.*", "$1");
            }
            if (!value.contains(":")) {
              value = "";
            }
          } else {
            value = "";
          }
        }
        if (!value.equals("")) {
          values.add("\"" + path + "/" + localName + "\"=\"" + value + "\"");
        }
      }
    }

    return s;
  }
  @Override
  public StartElement startElement(final StartElement element) throws XMLStreamException {
    final String curPath = parser.getCurPath();
    if (this.inside) {
      this.deepLevel++;
      writeElement(element);

      final int attCount = element.getAttributeCount();
      for (int i = 0; i < attCount; i++) {
        final Attribute curAtt = element.getAttribute(i);
        writeAttribute(
            curAtt.getNamespace(),
            element.getLocalName(),
            curAtt.getLocalName(),
            curAtt.getValue(),
            curAtt.getPrefix());
      }
    } else {
      if (curPath.endsWith("components/component")) {
        final int indexObjid = element.indexOfAttribute(null, "objid");
        final int indexHref = element.indexOfAttribute(Constants.XLINK_NS_URI, "href");
        if (!(indexObjid > -1 && element.getAttribute(indexObjid).getValue().length() > 0
            || indexHref > -1
                && Utility.getId(element.getAttribute(indexHref).getValue()).length() > 0)) {

          // start new component if there is no ID
          final ByteArrayOutputStream out = new ByteArrayOutputStream();

          this.writer = XmlUtility.createXmlStreamWriter(out);
          outputStreams.add(out);

          this.inside = true;
          this.deepLevel++;
          writeElement(element);

          final int attCount = element.getAttributeCount();
          for (int i = 0; i < attCount; i++) {
            final Attribute curAtt = element.getAttribute(i);
            writeAttribute(
                curAtt.getNamespace(),
                element.getLocalName(),
                curAtt.getLocalName(),
                curAtt.getValue(),
                curAtt.getPrefix());
          }
        }
      }
    }
    return element;
  }
  @Override
  public EndElement endElement(final EndElement element) throws XMLStreamException {
    final String curPath = parser.getCurPath();

    if (this.inside) {
      writer.writeEndElement();
      this.deepLevel--;

      final String ns = element.getNamespace();
      List nsTrace = nsuris.get(ns);

      if (nsTrace != null
          && (nsTrace.get(2) == null || nsTrace.get(2).equals(element.getPrefix()))
          && nsTrace.get(1).equals(element.getLocalName())
          && (Integer) nsTrace.get(0) == this.deepLevel + 1) {

        nsuris.remove(ns);
      }

      // attribute namespaces
      // TODO iteration is a hack, use
      // javax.xml.namespace.NamespaceContext
      Iterator<String> it = nsuris.keySet().iterator();
      final Collection<String> toRemove = new ArrayList<String>();
      while (it.hasNext()) {
        final String key = it.next();
        nsTrace = nsuris.get(key);
        if ((Integer) nsTrace.get(0) == this.deepLevel + 1) {
          toRemove.add(key);
        }
      }
      it = toRemove.iterator();
      while (it.hasNext()) {
        final String key = it.next();
        nsuris.remove(key);
      }
      if (curPath.endsWith("components/component")) {
        this.inside = false;
        writer.flush();
        writer.close();
      }
    }
    return element;
  }
  @Override
  public StartElement startElement(final StartElement element)
      throws TripleStoreSystemException, WebserverSystemException, InvalidContentException {
    final String curPath = parser.getCurPath();
    if (curPath.startsWith(this.componentPath) && curPath.equals(this.componentPath)) {
      // do my job
      // save componentId
      final int indexObjid = element.indexOfAttribute(null, "objid");
      final int indexHref = element.indexOfAttribute(Constants.XLINK_NS_URI, "href");
      if (indexObjid >= 0 || indexHref >= 0) {
        final String componentId =
            indexObjid >= 0
                ? element.getAttribute(indexObjid).getValue()
                : Utility.getId(element.getAttribute(indexHref).getValue());

        if (componentId.length() > 0) {
          // check if component exists
          boolean componentExists = false;
          final List<String> existingComponents =
              TripleStoreUtility.getInstance().getComponents(this.itemId);
          for (final String existingComponent : existingComponents) {
            if (existingComponent.equals(componentId)) {
              componentExists = true;
              break;
            }
          }
          if (!componentExists) {
            throw new InvalidContentException(
                "Component with id "
                    + componentId
                    + " does not exist in item "
                    + this.itemId
                    + '.');
          }
        }
      }
    }
    return element;
  }
  /**
   * Parser hits an XML end element.
   *
   * @param element StAX EndElement
   * @return StAX EndElement
   */
  @Override
  public EndElement endElement(final EndElement element) throws WebserverSystemException {

    final String currentPath = parser.getCurPath();

    if (xpathContentStream.equals(currentPath)) {

      this.parsingContent = false;

      if (this.hasContent) {
        final Map<String, Object> outputStreams = this.contentHandler.getOutputStreams();

        // MultipleExtractor could deliver a list of stream. But it
        // should be only possible to extract one with this parser
        // chain.
        if (outputStreams.size() > 1) {
          LOGGER.warn("Multiple content-streams.");
        }
        final Iterator<String> it = outputStreams.keySet().iterator();
        final ByteArrayOutputStream outStream =
            (ByteArrayOutputStream) outputStreams.get(it.next());

        try {
          this.content.setContent(outStream.toString(XmlUtility.CHARACTER_ENCODING));
        } catch (final UnsupportedEncodingException e) {
          throw new WebserverSystemException("Application default encoding not supported.", e);
        }
        this.hasContent = false;
        this.contentHandler = null;
      }
      this.contentStream.setContent(this.content);
    } else {
      if (this.parsingContent && this.hasContent) {
        this.contentHandler.endElement(element);
      }
    }

    return element;
  }
  /**
   * Parser hits an XML start element.
   *
   * @param element StartElement from StAX parser
   * @return StAX StartElement
   */
  @Override
  public StartElement startElement(final StartElement element)
      throws InvalidContentException, MissingAttributeValueException, WebserverSystemException {

    if (this.parsingContent) {
      if (this.contentHandler == null) {
        // reached first element after content-stream root element
        this.contentHandler =
            new MultipleExtractor(
                this.xpathContentStream + '/' + element.getLocalName(), this.parser);
      }
      this.hasContent = true;
      this.contentHandler.startElement(element);
    } else {
      final String currentPath = parser.getCurPath();
      if (currentPath.equals(this.xpathContentStream)) {
        if (LOGGER.isDebugEnabled()) {
          LOGGER.debug("Parser reached " + currentPath);
        }
        this.parsingContent = true;

        this.contentStream = new ContentStreamCreate();

        this.contentStream.setName(getAttributeValue(element, null, "name"));
        this.contentStream.setMimeType(getAttributeValue(element, null, "mime-type"));
        // this seams strange (title is a href attribute which should
        // be ignored)
        this.contentStream.setTitle(getAttributeValue(element, Constants.XLINK_NS_URI, "title"));

        this.content = new BinaryContent();
        this.content.setStorageType(getAttributeValue(element, null, "storage"));
        this.content.setDataLocation(getAttributeValue(element, Constants.XLINK_NS_URI, "href"));
      }
    }

    return element;
  }
  @Override
  public StartElement startElement(final StartElement element) throws XMLStreamException {
    final String elementName = element.getLocalName();
    if ("component".equals(elementName)) {
      this.inComponent = true;
      if (this.pids != null) {
        this.componentId = pids.get(this.number);
        this.number++;
      } else {
        final int index = element.indexOfAttribute(null, "objid");
        if (index != -1) {
          final String value = element.getAttribute(index).getValue();
          if (value != null && value.length() > 0) {
            this.componentId = value;
          }
        }
      }
    }

    if (!this.inside) {
      final String currentPath = parser.getCurPath();
      if (paths.containsKey(currentPath)) {
        if (this.insideLevel != 0) {
          throw new XMLStreamException("insideLevel != 0: " + this.insideLevel);
        }

        this.inside = true;
        final ByteArrayOutputStream out = new ByteArrayOutputStream();
        this.writer = newInitializedWriter(out);

        final String attributeName = paths.get(currentPath);
        if (this.inComponent) {
          if (this.components == null) {
            this.components = new HashMap<String, Map>();
            outputStreams.put("components", this.components);
          }
          final Map<String, Object> component;
          if (components.containsKey(this.componentId)) {
            component = (HashMap) components.get(this.componentId);
          } else {
            component = new HashMap<String, Object>();
            components.put(this.componentId, component);
          }

          if (attributeName == null) {
            component.put(elementName, out);
          } else {
            final String attributeValue = getAttributeValue(element, null, attributeName);
            if ("md-record".equals(elementName)) {
              Map<String, OutputStream> mdRecords = components.get(this.components);
              if (mdRecords == null) {
                mdRecords = new HashMap<String, OutputStream>();
                component.put("md-records", mdRecords);
              }
              mdRecords.put(attributeValue, out);
            } else {
              component.put(attributeValue, out);
            }
          }
        } else {
          if (attributeName == null) {
            outputStreams.put(elementName, out);
          } else {
            final String attributeValue = getAttributeValue(element, null, attributeName);
            if ("md-record".equals(elementName)) {
              if (this.metadata == null) {
                this.metadata = new HashMap<String, OutputStream>();
                outputStreams.put("md-records", this.metadata);
              }
              metadata.put(attributeValue, out);
            } else {
              outputStreams.put(attributeValue, out);
            }
          }
        }
      }
    }

    // write start element with attributes (and implicit neccessary
    // namespace declarations due to the repairing xml writer
    if (this.inside) {
      String namespace = element.getNamespace();
      if (namespace != null && !namespaceMap.containsKey(namespace)) {
        final String prefix = element.getPrefix();
        if (prefix != null) {
          writer.setPrefix(prefix, element.getNamespace());
        } else {
          writer.setDefaultNamespace(element.getNamespace());
        }
      }

      if (!("md-record".equals(elementName) && paths.containsKey(parser.getCurPath()))) {
        writer.writeStartElement(element.getNamespace(), elementName);
      }
      final int attCount = element.getAttributeCount();
      for (int i = 0; i < attCount; i++) {
        final Attribute curAtt = element.getAttribute(i);
        namespace = curAtt.getNamespace();
        if (namespace != null && !namespaceMap.containsKey(namespace)) {
          // Prefix is not null. (FRS)
          writer.setPrefix(curAtt.getPrefix(), namespace);
        }
        if (!("md-record".equals(elementName) && paths.containsKey(parser.getCurPath()))) {
          writer.writeAttribute(namespace, curAtt.getLocalName(), curAtt.getValue());
        }
      }
      this.insideLevel++;
    }

    // this has to be the last handler
    return element;
  }