github.com/fluhus/gostuff@v0.4.1-0.20240331134726-be71864f2b5d/xmlnode/node.go (about)

     1  package xmlnode
     2  
     3  import (
     4  	"encoding/xml"
     5  )
     6  
     7  // DESIGN NOTE:
     8  // The idea behind the somewhat clumsy interface (rather than something like
     9  // the empty Token interface) is to eliminate some of the need for type checks.
    10  //
    11  // For example, if you need to traverse the node tree, you don't need to check
    12  // if a node is a Tag node before you call its children. Or if you need to
    13  // search for a specific text, you don't need to check which nodes are actually
    14  // text nodes.
    15  //
    16  // You can, of course, check node types (returned by Type()) if you still need
    17  // to.
    18  
    19  // DESIGN NOTE (2):
    20  // The Type() function is used instead of exported types to avoid cluttering
    21  // the package's godoc.
    22  
    23  // A Node represents a single XML node. Can be one of: Root, Tag, Text, Comment,
    24  // ProcInst or Directive.
    25  //
    26  // String methods return empty strings when called on a non-relevant node. For
    27  // example, calling TagName() on a Text node or vise versa. The Children()
    28  // method returns nil for non Tag or Root nodes. The Attr() method returns nil
    29  // for non Tag nodes.
    30  //
    31  // Parent node is nil only in Root.
    32  type Node interface {
    33  	// Parent of the current node. Nil for root node.
    34  	Parent() Node
    35  
    36  	// Tag name of tag nodes of the form <tagname>...</tagname>. Empty for
    37  	// other node types.
    38  	TagName() string
    39  
    40  	// Attributes of tag nodes. Nil for other node types.
    41  	Attr() []*xml.Attr
    42  
    43  	// Child nodes of root and tag nodes. Nil for other node types.
    44  	Children() []Node
    45  
    46  	// Text data of text nodes. Empty for other node types.
    47  	Text() string
    48  
    49  	// Comment data of comments of the form <!--comment-->. Does not include the
    50  	// <!-- and --> markers. Empty for other node types.
    51  	Comment() string
    52  
    53  	// Target of processing instructions of the form <?target inst?>.
    54  	// Empty for other node types.
    55  	Target() string
    56  
    57  	// Instruction of processing instructions of the form <?target inst?>.
    58  	// Empty for other node types.
    59  	Inst() string
    60  
    61  	// Directive of the form <!directive>. Does not include the <! and >
    62  	// markers. Empty for other node types.
    63  	Directive() string
    64  
    65  	// Type of this node. Returns one of: Root, Tag, Text, Comment, ProcInst
    66  	// or Directive.
    67  	Type() int
    68  }
    69  
    70  // Represents the root node of an XML tree. Only has children, no other
    71  // properties.
    72  type root struct {
    73  	children []Node
    74  }
    75  
    76  func (n *root) Parent() Node      { return nil }
    77  func (n *root) TagName() string   { return "" }
    78  func (n *root) Attr() []*xml.Attr { return nil }
    79  func (n *root) Children() []Node  { return n.children }
    80  func (n *root) Text() string      { return "" }
    81  func (n *root) Comment() string   { return "" }
    82  func (n *root) Target() string    { return "" }
    83  func (n *root) Inst() string      { return "" }
    84  func (n *root) Directive() string { return "" }
    85  func (n *root) Type() int         { return Root }
    86  
    87  // Represents a start-end element, along with its children.
    88  type tag struct {
    89  	parent   Node
    90  	tagName  string
    91  	attr     []*xml.Attr
    92  	children []Node
    93  }
    94  
    95  func (n *tag) Parent() Node      { return n.parent }
    96  func (n *tag) TagName() string   { return n.tagName }
    97  func (n *tag) Attr() []*xml.Attr { return n.attr }
    98  func (n *tag) Children() []Node  { return n.children }
    99  func (n *tag) Text() string      { return "" }
   100  func (n *tag) Comment() string   { return "" }
   101  func (n *tag) Target() string    { return "" }
   102  func (n *tag) Inst() string      { return "" }
   103  func (n *tag) Directive() string { return "" }
   104  func (n *tag) Type() int         { return Tag }
   105  
   106  // Represents raw text data, in which XML escape sequences have been replaced
   107  // by the characters they represent.
   108  type text struct {
   109  	parent Node
   110  	text   string
   111  }
   112  
   113  func (n *text) Parent() Node      { return n.parent }
   114  func (n *text) TagName() string   { return "" }
   115  func (n *text) Attr() []*xml.Attr { return nil }
   116  func (n *text) Children() []Node  { return nil }
   117  func (n *text) Text() string      { return n.text }
   118  func (n *text) Comment() string   { return "" }
   119  func (n *text) Target() string    { return "" }
   120  func (n *text) Inst() string      { return "" }
   121  func (n *text) Directive() string { return "" }
   122  func (n *text) Type() int         { return Text }
   123  
   124  // A Comment represents an XML comment of the form <!--comment-->. The string
   125  // does not include the <!-- and --> comment markers.
   126  type comment struct {
   127  	parent  Node
   128  	comment string
   129  }
   130  
   131  func (n *comment) Parent() Node      { return n.parent }
   132  func (n *comment) TagName() string   { return "" }
   133  func (n *comment) Attr() []*xml.Attr { return nil }
   134  func (n *comment) Children() []Node  { return nil }
   135  func (n *comment) Text() string      { return "" }
   136  func (n *comment) Comment() string   { return n.comment }
   137  func (n *comment) Target() string    { return "" }
   138  func (n *comment) Inst() string      { return "" }
   139  func (n *comment) Directive() string { return "" }
   140  func (n *comment) Type() int         { return Comment }
   141  
   142  // Represents an XML processing instruction of the form <?target inst?>.
   143  type procInst struct {
   144  	parent Node
   145  	target string
   146  	inst   string
   147  }
   148  
   149  func (n *procInst) Parent() Node      { return n.parent }
   150  func (n *procInst) TagName() string   { return "" }
   151  func (n *procInst) Attr() []*xml.Attr { return nil }
   152  func (n *procInst) Children() []Node  { return nil }
   153  func (n *procInst) Text() string      { return "" }
   154  func (n *procInst) Comment() string   { return "" }
   155  func (n *procInst) Target() string    { return n.target }
   156  func (n *procInst) Inst() string      { return n.inst }
   157  func (n *procInst) Directive() string { return "" }
   158  func (n *procInst) Type() int         { return ProcInst }
   159  
   160  // Represents an XML directive of the form <!text>. The string does not include
   161  // the <! and > markers.
   162  type directive struct {
   163  	parent    Node
   164  	directive string
   165  }
   166  
   167  func (n *directive) Parent() Node      { return n.parent }
   168  func (n *directive) TagName() string   { return "" }
   169  func (n *directive) Attr() []*xml.Attr { return nil }
   170  func (n *directive) Children() []Node  { return nil }
   171  func (n *directive) Text() string      { return "" }
   172  func (n *directive) Comment() string   { return "" }
   173  func (n *directive) Target() string    { return "" }
   174  func (n *directive) Inst() string      { return "" }
   175  func (n *directive) Directive() string { return n.directive }
   176  func (n *directive) Type() int         { return Directive }
   177  
   178  // Possible return values of Type().
   179  const (
   180  	Root = iota
   181  	Tag
   182  	Text
   183  	Comment
   184  	ProcInst
   185  	Directive
   186  )