github.com/boki/go-xmp@v1.0.1/xmp/filter.go (about)

     1  // Copyright (c) 2017-2018 Alexander Eichhorn
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License"): you may
     4  // not use this file except in compliance with the License. You may obtain
     5  // a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    11  // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    12  // License for the specific language governing permissions and limitations
    13  // under the License.
    14  
    15  package xmp
    16  
    17  import (
    18  	"fmt"
    19  	"reflect"
    20  	"strings"
    21  )
    22  
    23  type Filter struct {
    24  	include NamespaceList
    25  	exclude NamespaceList
    26  }
    27  
    28  func NewFilter(include, exclude NamespaceList) *Filter {
    29  	return &Filter{
    30  		include: include,
    31  		exclude: exclude,
    32  	}
    33  }
    34  
    35  func ParseFilterStrict(s string) (*Filter, error) {
    36  	f := NewFilter(nil, nil)
    37  	if len(s) == 0 {
    38  		return f, nil
    39  	}
    40  	for _, v := range strings.Split(s, ",") {
    41  		if v == "" {
    42  			continue
    43  		}
    44  		switch v[0] {
    45  		case '-':
    46  			v = v[1:]
    47  			// 1st try parsing as group
    48  			if g := ParseNamespaceGroup(v); g != NoMetadata {
    49  				f.exclude = append(f.exclude, g.Namespaces()...)
    50  				break
    51  			}
    52  			// 2nd try as namespace
    53  			if ns, err := GetNamespace(v); err == nil {
    54  				f.exclude = append(f.exclude, ns)
    55  			} else {
    56  				return nil, fmt.Errorf("no registered xmp namespace %s", v)
    57  			}
    58  		case '+':
    59  			v = v[1:]
    60  			fallthrough
    61  		default:
    62  			// 1st try parsing as group
    63  			if g := ParseNamespaceGroup(v); g != NoMetadata {
    64  				f.include = append(f.include, g.Namespaces()...)
    65  				break
    66  			}
    67  			// 2nd try as namespace
    68  			if ns, err := GetNamespace(v); err == nil {
    69  				f.include = append(f.include, ns)
    70  			} else {
    71  				return nil, fmt.Errorf("no registered xmp namespace %s", v)
    72  			}
    73  		}
    74  	}
    75  	return f, nil
    76  }
    77  
    78  func ParseFilter(s string) *Filter {
    79  	f := NewFilter(nil, nil)
    80  	if len(s) == 0 {
    81  		return f
    82  	}
    83  	for _, v := range strings.Split(s, ",") {
    84  		if v == "" {
    85  			continue
    86  		}
    87  		switch v[0] {
    88  		case '-':
    89  			v = v[1:]
    90  			// 1st try parsing as group
    91  			if g := ParseNamespaceGroup(v); g != NoMetadata {
    92  				f.exclude = append(f.exclude, g.Namespaces()...)
    93  				break
    94  			}
    95  			// 2nd try as namespace
    96  			if ns, err := GetNamespace(v); err == nil {
    97  				f.exclude = append(f.exclude, ns)
    98  			} else {
    99  				f.exclude = append(f.exclude, &Namespace{Name: v})
   100  			}
   101  		case '+', ' ': // treat space as '+' to because of URL unescaping
   102  			v = v[1:]
   103  			fallthrough
   104  		default:
   105  			// 1st try parsing as group
   106  			if g := ParseNamespaceGroup(v); g != NoMetadata {
   107  				f.include = append(f.include, g.Namespaces()...)
   108  				break
   109  			}
   110  			// 2nd try as namespace
   111  			if ns, err := GetNamespace(v); err == nil {
   112  				f.include = append(f.include, ns)
   113  			} else {
   114  				f.include = append(f.include, &Namespace{Name: v})
   115  			}
   116  		}
   117  	}
   118  	return f
   119  }
   120  
   121  func (x *Filter) UnmarshalText(b []byte) error {
   122  	f := ParseFilter(string(b))
   123  	*x = *f
   124  	return nil
   125  }
   126  
   127  func (x Filter) String() string {
   128  	s := make([]string, 0, len(x.include)+len(x.exclude))
   129  	for _, v := range x.include {
   130  		s = append(s, fmt.Sprintf("+%s", v.GetName()))
   131  	}
   132  	for _, v := range x.exclude {
   133  		s = append(s, fmt.Sprintf("-%s", v.GetName()))
   134  	}
   135  	return strings.Join(s, ",")
   136  }
   137  
   138  func (x Filter) Apply(d *Document) bool {
   139  	var removed bool
   140  	if len(x.include) > 0 {
   141  		r := d.FilterNamespaces(x.include)
   142  		removed = removed || r
   143  	}
   144  	if len(x.exclude) > 0 {
   145  		r := d.RemoveNamespaces(x.exclude)
   146  		removed = removed || r
   147  	}
   148  	return removed
   149  }
   150  
   151  // converter function for Gorilla schema; will become unnecessary once
   152  // https://github.com/gorilla/schema/issues/57 is fixed
   153  //
   154  // register with decoder.RegisterConverter(Filter(""), ConvertFilter)
   155  func ConvertFilter(value string) reflect.Value {
   156  	v := ParseFilter(value)
   157  	return reflect.ValueOf(*v)
   158  }