docs: @SuppressWarnings({ "checkstyle:npathcomplexity", "checkstyle:cyclomaticcomplexity" })
      public static IClasspathEntry elementDecode(Element element, String projectName, IPath projectRootAbsoluteFullPath,
              Map<IPath, UnknownXmlElements> unknownElements) {
          final IPath projectPath = projectRootAbsoluteFullPath;
          final NamedNodeMap attributes = element.getAttributes();
          final NodeList children = element.getChildNodes();
          final boolean[] foundChildren = new boolean[children.getLength()];
          final String kindAttr = removeAttribute(ClasspathEntry.TAG_KIND, attributes);
          final String pathAttr = removeAttribute(ClasspathEntry.TAG_PATH, attributes);
  
          // ensure path is absolute
          IPath path = new Path(pathAttr);
          final int kind = kindFromString(kindAttr);
          if (kind != IClasspathEntry.CPE_VARIABLE && kind != IClasspathEntry.CPE_CONTAINER && !path.isAbsolute()) {
              if (!(path.segmentCount() > 0 && path.segment(0).equals(ClasspathEntry.DOT_DOT))) {
                  path = projectPath.append(path);
              }
          }
          // source attachment info (optional)
          IPath sourceAttachmentPath = element.hasAttribute(ClasspathEntry.TAG_SOURCEPATH)
                  ? new Path(removeAttribute(ClasspathEntry.TAG_SOURCEPATH, attributes)) : null;
          if (kind != IClasspathEntry.CPE_VARIABLE && sourceAttachmentPath != null && !sourceAttachmentPath.isAbsolute()) {
              sourceAttachmentPath = projectPath.append(sourceAttachmentPath);
          }
          final IPath sourceAttachmentRootPath = element.hasAttribute(ClasspathEntry.TAG_ROOTPATH)
                  ? new Path(removeAttribute(ClasspathEntry.TAG_ROOTPATH, attributes)) : null;
  
          // exported flag (optional)
          final boolean isExported = removeAttribute(ClasspathEntry.TAG_EXPORTED, attributes).equals("true"); //$NON-NLS-1$
  
          // inclusion patterns (optional)
          IPath[] inclusionPatterns = decodePatterns(attributes, ClasspathEntry.TAG_INCLUDING);
          if (inclusionPatterns == null) {
              inclusionPatterns = ClasspathEntry.INCLUDE_ALL;
          }
  
          // exclusion patterns (optional)
          IPath[] exclusionPatterns = decodePatterns(attributes, ClasspathEntry.TAG_EXCLUDING);
          if (exclusionPatterns == null) {
              exclusionPatterns = ClasspathEntry.EXCLUDE_NONE;
          }
  
          // access rules (optional)
          NodeList attributeList = getChildAttributes(ClasspathEntry.TAG_ACCESS_RULES, children, foundChildren);
          IAccessRule[] accessRules = decodeAccessRules(attributeList);
  
          // backward compatibility
          if (accessRules == null) {
              accessRules = getAccessRules(inclusionPatterns, exclusionPatterns);
          }
  
          // combine access rules (optional)
          final boolean combineAccessRestrictions = !removeAttribute(ClasspathEntry.TAG_COMBINE_ACCESS_RULES, attributes).equals("false"); //$NON-NLS-1$
  
          // extra attributes (optional)
          attributeList = getChildAttributes(ClasspathEntry.TAG_ATTRIBUTES, children, foundChildren);
          final IClasspathAttribute[] extraAttributes = decodeExtraAttributes(attributeList);
  
          // custom output location
          final IPath outputLocation = element.hasAttribute(ClasspathEntry.TAG_OUTPUT)
                  ? projectPath.append(removeAttribute(ClasspathEntry.TAG_OUTPUT, attributes)) : null;
  
          String[] unknownAttributes = null;
          ArrayList<String> unknownChildren = null;
  
          if (unknownElements != null) {
              // unknown attributes
              final int unknownAttributeLength = attributes.getLength();
              if (unknownAttributeLength != 0) {
                  unknownAttributes = new String[unknownAttributeLength * 2];
                  for (int i = 0; i < unknownAttributeLength; i++) {
                      final Node attribute = attributes.item(i);
                      unknownAttributes[i * 2] = attribute.getNodeName();
                      unknownAttributes[i * 2 + 1] = attribute.getNodeValue();
                  }
              }
  
              // unknown children
              for (int i = 0, length = foundChildren.length; i < length; i++) {
                  if (!foundChildren[i]) {
                      final Node node = children.item(i);
                      if (node.getNodeType() != Node.ELEMENT_NODE) {
                          continue;
                      }
                      if (unknownChildren == null) {
                          unknownChildren = new ArrayList<>();
                      }
                      final StringBuffer buffer = new StringBuffer();
                      decodeUnknownNode(node, buffer);
                      unknownChildren.add(buffer.toString());
                  }
              }
          }
  
          // recreate the CP entry
          IClasspathEntry entry = null;
          switch (kind) {
  
          case IClasspathEntry.CPE_PROJECT:
              /*
               * IPackageFragmentRoot.K_SOURCE, IClasspathEntry.CPE_PROJECT, path, ClasspathEntry.INCLUDE_ALL, // inclusion patterns
               * ClasspathEntry.EXCLUDE_NONE, // exclusion patterns null, // source attachment null, // source attachment root null, // specific output
               * folder
               */
              entry = new ClasspathEntry(IPackageFragmentRoot.K_SOURCE, IClasspathEntry.CPE_PROJECT, path, ClasspathEntry.INCLUDE_ALL,
                      ClasspathEntry.EXCLUDE_NONE, null, null, null, isExported, accessRules, combineAccessRestrictions, extraAttributes);
              break;
          case IClasspathEntry.CPE_LIBRARY:
              entry = JavaCore.newLibraryEntry(path, sourceAttachmentPath, sourceAttachmentRootPath, accessRules, extraAttributes, isExported);
              break;
          case IClasspathEntry.CPE_SOURCE:
              // must be an entry in this project or specify another project
              final String projSegment = path.segment(0);
              if (projSegment != null && projSegment.equals(projectName)) {
                  // this project
                  entry = JavaCore.newSourceEntry(path, inclusionPatterns, exclusionPatterns, outputLocation, extraAttributes);
              } else {
                  if (path.segmentCount() == 1) {
                      // another project
                      entry = JavaCore.newProjectEntry(path, accessRules, combineAccessRestrictions, extraAttributes, isExported);
                  } else {
                      // an invalid source folder
                      entry = JavaCore.newSourceEntry(path, inclusionPatterns, exclusionPatterns, outputLocation, extraAttributes);
                  }
              }
              break;
          case IClasspathEntry.CPE_VARIABLE:
              entry = JavaCore.newVariableEntry(path, sourceAttachmentPath, sourceAttachmentRootPath, accessRules, extraAttributes, isExported);
              break;
          case IClasspathEntry.CPE_CONTAINER:
              entry = JavaCore.newContainerEntry(path, accessRules, extraAttributes, isExported);
              break;
          case ClasspathEntry.K_OUTPUT:
              if (!path.isAbsolute()) {
                  return null;
              }
              /*
               * ClasspathEntry.EXCLUDE_NONE, null, // source attachment null, // source attachment root null, // custom output location false, null, //
               * no access rules false, // no accessible files to combine
               */
              entry = new ClasspathEntry(ClasspathEntry.K_OUTPUT, IClasspathEntry.CPE_LIBRARY, path, ClasspathEntry.INCLUDE_ALL,
                      ClasspathEntry.EXCLUDE_NONE, null, null, null, false, null, false, ClasspathEntry.NO_EXTRA_ATTRIBUTES);
              break;
          default:
              throw new AssertionFailedException(Messages.bind(Messages.classpath_unknownKind, kindAttr));
          }
  
          if (unknownAttributes != null || unknownChildren != null) {
              final UnknownXmlElements unknownXmlElements = new UnknownXmlElements();
              unknownXmlElements.attributes = unknownAttributes;
              unknownXmlElements.children = unknownChildren;
              if (unknownElements != null) {
              	unknownElements.put(path, unknownXmlElements);
              }
          }
  
          return entry;
      }