private static PyDebugValue parseValue(final XppReader reader, PyFrameAccessor frameAccessor) throws PyDebuggerException {
    if (!"var".equals(reader.getNodeName())) {
      throw new PyDebuggerException("Expected <var>, found " + reader.getNodeName());
    }

    final String name = readString(reader, "name", null);
    final String isErrorOnEval = readString(reader, "isErrorOnEval", "");
    if (HIDDEN_TYPES.contains(name)) {
      return new PyDebugValue(name, null, "", "", false, null, false,
                              false, "True".equals(isErrorOnEval), null, frameAccessor);
    }

    final String type = readString(reader, "type", null);
    final String qualifier = readString(reader, "qualifier", ""); //to be able to get the fully qualified type if necessary

    String value = readString(reader, "value", null);
    final String isContainer = readString(reader, "isContainer", "");
    final String isReturnedValue = readString(reader, "isRetVal", "");
    final String isIPythonHidden = readString(reader, "isIPythonHidden", "");
    String typeRendererId = readString(reader, "typeRendererId", "");
    String shape = readString(reader, "shape", "");

    if (value.startsWith(type + ": ")) {  // drop unneeded prefix
      value = value.substring(type.length() + 2);
    }
    if (shape.isEmpty()) shape = null;
    if (typeRendererId.isEmpty()) typeRendererId = null;
    if (type.equals("DataFrame")) {
      return new DataFrameDebugValue(name, type, qualifier, value, "True".equals(isContainer), shape, "True".equals(isReturnedValue),
                                     "True".equals(isIPythonHidden), "True".equals(isErrorOnEval), typeRendererId, frameAccessor);
    }
    return new PyDebugValue(name, type, qualifier, value, "True".equals(isContainer), shape, "True".equals(isReturnedValue),
                            "True".equals(isIPythonHidden), "True".equals(isErrorOnEval), typeRendererId, frameAccessor);
  }
private static PyDebugValue parseValue(final XppReader reader, PyFrameAccessor frameAccessor)