private StackTraceElement[] parseStackTrace(Node stackTraceNode) {
    ArrayList<StackTraceElement> elements = new ArrayList<StackTraceElement>();

    NodeList elementNodeList = stackTraceNode.getChildNodes();
    for (int i = 0; i < elementNodeList.getLength(); i++) {
      Node xmlNode = elementNodeList.item(i);
      if (xmlNode.getNodeType() == Node.ELEMENT_NODE && xmlNode.getNodeName().equals("e")) {

        String className = XmlUtils.getNodeAttribute(xmlNode, "c");
        String methodName = XmlUtils.getNodeAttribute(xmlNode, "m");
        String fileName = XmlUtils.getNodeAttribute(xmlNode, "f");
        String strLineNumber = XmlUtils.getNodeAttribute(xmlNode, "l");

        if (className == null) {
          className = "";
        }
        if (methodName == null) {
          methodName = "";
        }

        Integer lineNumber = 0;
        if (strLineNumber != null) {
          lineNumber = Integer.parseInt(strLineNumber);
        }
        StackTraceElement element =
            new StackTraceElement(className, methodName, fileName, lineNumber);

        elements.add(element);
      }
    }
    return elements.toArray(new StackTraceElement[] {});
  }
  private ReportNode parse(Node xmlNode) throws Exception {
    if (!"r".equals(xmlNode.getNodeName())) throw new Exception("The report has errors");

    ReportNode rn;

    String classPath = NODE_CLASS_PATH + XmlUtils.getNodeAttribute(xmlNode, "c");

    Class<?> clazz = Class.forName(classPath);
    rn = (ReportNode) clazz.newInstance();

    rn.setIcon(XmlUtils.getNodeAttribute(xmlNode, "i"));
    rn.setLevel(XmlUtils.getNodeAttribute(xmlNode, "l"));
    rn.setTitle(XmlUtils.getChildNodeText(xmlNode, "t"));
    rn.setHint(XmlUtils.getChildNodeText(xmlNode, "h"));

    String time = XmlUtils.getNodeAttribute(xmlNode, "t");
    if (time != null) {
      rn.setDate(new Date(Long.parseLong(time)));
    }

    String debug = XmlUtils.getNodeAttribute(xmlNode, "d");
    if (debug != null) {
      rn.setDebug(Boolean.parseBoolean(debug));
    }

    if (rn instanceof TextReportNode) {
      TextReportNode textNode = (TextReportNode) rn;
      textNode.setDetails(XmlUtils.getChildNodeText(xmlNode, "d"));
    } else if (rn instanceof BranchReportNode) {
      BranchReportNode branchNode = (BranchReportNode) rn;
      Node childrenNodeContainer = XmlUtils.getChildNode(xmlNode, "c");
      branchNode.setChildNodes(new LinkedList<ReportNode>());

      if (childrenNodeContainer != null) {
        NodeList childNodes = childrenNodeContainer.getChildNodes();

        for (int i = 0; i < childNodes.getLength(); i++) {
          Node childNode = childNodes.item(i);
          if (childNode.getNodeType() == Node.ELEMENT_NODE && childNode.getNodeName().equals("r")) {
            branchNode.getChildNodes().add(parse(childNode));
          }
        }
      }
    }
    if (rn instanceof ExceptionReportNode) {
      ExceptionReportNode exceptionNode = (ExceptionReportNode) rn;
      Node exceptionInfoXmlNode = XmlUtils.getChildNode(xmlNode, "e");
      if (exceptionInfoXmlNode != null) {
        exceptionNode.setException(parseExceptionInfo(exceptionInfoXmlNode));
      }
    }

    return rn;
  }
  @Override
  public List<ReportReason> decodeReasons(String reasonsString) throws Exception {
    if (reasonsString != null && !reasonsString.isEmpty()) {
      try {
        Node xmlNode = getFirstXmlNode(reasonsString);

        List<ReportReason> reasons = new LinkedList<ReportReason>();
        NodeList reasonNodes = xmlNode.getChildNodes();
        for (int i = 0; i < reasonNodes.getLength(); i++) {
          Node reasonNode = reasonNodes.item(i);
          if (reasonNode.getNodeType() == Node.ELEMENT_NODE
              && reasonNode.getNodeName().equals("reason")) {
            ReportReason reason = new ReportReason();
            reason.setLevel(XmlUtils.getNodeAttribute(reasonNode, "level"));
            reason.setReason(reasonNode.getTextContent());
            reasons.add(reason);
          }
        }
        return reasons;
      } catch (Exception e) {
        return null;
      }
    }
    return null;
  }
  private ExceptionInfo parseExceptionInfo(Node xmlNode) {
    ExceptionInfo info = new ExceptionInfo();
    info.setClassName(XmlUtils.getChildNodeText(xmlNode, "n"));
    info.setMessageName(XmlUtils.getChildNodeText(xmlNode, "m"));
    Node stackTraceNode = XmlUtils.getChildNode(xmlNode, "s");
    if (stackTraceNode != null) {
      String stackMore = XmlUtils.getNodeAttribute(stackTraceNode, "more");
      if (stackMore != null) {
        info.setMoreStackTraceElements(Integer.parseInt(stackMore));
      }
      info.setStackTrace(parseStackTrace(stackTraceNode));
    }

    Node causeNode = XmlUtils.getChildNode(xmlNode, "c");
    if (causeNode != null) {
      info.setCause(parseExceptionInfo(causeNode));
    }
    return info;
  }