tdcommon/src/main/java/thredds/server/catalog/builder/DatasetScanConfigBuilder.java
private List<DatasetScanConfig.Filter> readDatasetScanFilter(Element filterElem) {
    List<DatasetScanConfig.Filter> filters = new ArrayList<>();
    if (filterElem == null) return null;

    for (Element curElem : filterElem.getChildren()) {
      String regExpAttVal = curElem.getAttributeValue("regExp");
      String wildcardAttVal = curElem.getAttributeValue("wildcard");
      String lastModLimitAttValS = curElem.getAttributeValue("lastModLimitInMillis");
      if (regExpAttVal == null && wildcardAttVal == null && lastModLimitAttValS == null) {
        // If no regExp or wildcard attributes, skip this selector.
        errlog.format("WARN: readDatasetScanFilter(): no regExp, wildcard, or lastModLimitInMillis attribute in filter child <%s>%n", curElem.getName());

      } else {
        // Determine if applies to atomic datasets, default true.
        String atomicAttVal = curElem.getAttributeValue("atomic");
        boolean atomic = (atomicAttVal == null || !atomicAttVal.equalsIgnoreCase("false"));

        // Determine if applies to collection datasets, default false.
        String collectionAttVal = curElem.getAttributeValue("collection");
        boolean notCollection = collectionAttVal == null || !collectionAttVal.equalsIgnoreCase("true");

        // Determine if include or exclude selectors.
        boolean includer = true;
        if (curElem.getName().equals("exclude")) {
          includer = false;
        } else if (!curElem.getName().equals("include")) {
          errlog.format("WARN: readDatasetScanFilter(): unhandled filter child <%s>.%n", curElem.getName());
          continue;
        }

        // check for errors
        long lastModLimitAttVal = -1;
        if (lastModLimitAttValS != null) {
          try {
            lastModLimitAttVal = Long.parseLong(lastModLimitAttValS);
          } catch (NumberFormatException e) {
            errlog.format("WARN: readDatasetScanFilter(): lastModLimitInMillis not valid <%s>.%n", curElem);
          }
        }

        filters.add(new DatasetScanConfig.Filter(regExpAttVal, wildcardAttVal, lastModLimitAttVal, atomic, !notCollection, includer));
      }
    }

    return filters;
  }
private List<DatasetScanConfig.Filter> readDatasetScanFilter(Element filterElem) {
    List<DatasetScanConfig.Filter> filters = new ArrayList<>();
    if (filterElem == null) return null;

    for (Element curElem : filterElem.getChildren()) {
      String regExpAttVal = curElem.getAttributeValue("regExp");
      String wildcardAttVal = curElem.getAttributeValue("wildcard");
      String lastModLimitAttValS = curElem.getAttributeValue("lastModLimitInMillis");
      if (regExpAttVal == null && wildcardAttVal == null && lastModLimitAttValS == null) {
        // If no regExp or wildcard attributes, skip this selector.
        errlog.format("WARN: readDatasetScanFilter(): no regExp, wildcard, or lastModLimitInMillis attribute in filter child <%s>%n", curElem.getName());

      } else {
        // Determine if applies to atomic datasets, default true.
        String atomicAttVal = curElem.getAttributeValue("atomic");
        boolean atomic = (atomicAttVal == null || !atomicAttVal.equalsIgnoreCase("false"));

        // Determine if applies to collection datasets, default false.
        String collectionAttVal = curElem.getAttributeValue("collection");
        boolean notCollection = collectionAttVal == null || !collectionAttVal.equalsIgnoreCase("true");

        // Determine if include or exclude selectors.
        boolean includer = true;
        if (curElem.getName().equals("exclude")) {
          includer = false;
        } else if (!curElem.getName().equals("include")) {
          errlog.format("WARN: readDatasetScanFilter(): unhandled filter child <%s>.%n", curElem.getName());
          continue;
        }

        // check for errors
        long lastModLimitAttVal = -1;
        if (lastModLimitAttValS != null) {
          try {
            lastModLimitAttVal = Long.parseLong(lastModLimitAttValS);
          } catch (NumberFormatException e) {
            errlog.format("WARN: readDatasetScanFilter(): lastModLimitInMillis not valid <%s>.%n", curElem);
          }
        }

        filters.add(new DatasetScanConfig.Filter(regExpAttVal, wildcardAttVal, lastModLimitAttVal, atomic, !notCollection, includer));
      }
    }

    return filters;
  }
/*
<xsd:element name="filter">
<xsd:complexType>
<xsd:choice>
<xsd:sequence minOccurs="0" maxOccurs="unbounded">
<xsd:element name="include" type="FilterSelectorType" minOccurs="0"/>
<xsd:element name="exclude" type="FilterSelectorType" minOccurs="0"/>
</xsd:sequence>
</xsd:choice>
</xsd:complexType>
</xsd:element>

<xsd:complexType name="FilterSelectorType">
<xsd:attribute name="regExp" type="xsd:string"/>
<xsd:attribute name="wildcard" type="xsd:string"/>
<xsd:attribute name="atomic" type="xsd:boolean"/>
<xsd:attribute name="collection" type="xsd:boolean"/>
</xsd:complexType>