@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;
  }
  /**
   * 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 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;
  }