code: public static Collection<AbstractAttribute> findAttributesByTagName(
              final boolean parallel, final String tagName,
              final AbstractHtml... fromTags) throws NullValueException {
  
          if (tagName == null) {
              throw new NullValueException("The tagName should not be null");
          }
  
          if (fromTags == null) {
              throw new NullValueException("The fromTags should not be null");
          }
  
          final Collection<Lock> locks = getReadLocks(fromTags);
          for (final Lock lock : locks) {
              lock.lock();
          }
          try {
              return getAllNestedChildrenIncludingParent(parallel, fromTags)
                      .filter(child -> {
                          return tagName.equals(child.getTagName())
                                  && child.getAttributes() != null;
                      }).map(child -> {
                          return child.getAttributes();
                      }).flatMap(attributes -> attributes.stream())
                      .collect(Collectors.toSet());
          } finally {
              for (final Lock lock : locks) {
                  lock.unlock();
              }
          }
  
      }
docs: Finds and returns the collection of attributes (including from nested
  tags) of the tags matching with the give tag name.
  
  @param parallel
  true to internally use parallel stream. If true it
  will split the finding task to different batches and
  will execute the batches in different threads in
  parallel consuming all CPUs. It will perform faster
  in finding from extremely large number of tags but at
  the same time it will less efficient in finding from
  small number of tags.
  
  @param tagName
  the name of the tag.
  @param fromTags
  from which the findings to be done.
  @return the collection of attributes of the tags matching with the given
  tag name.
  @throws NullValueException
  if the {@code tagName} or {@code fromTags}
  is null
  @since 3.0.0
  @author WFF