func (p *Model) streamIndex(proto string) gwutil.IntOption {
	var res gwutil.IntOption
	if showNode := xmlquery.FindOne(p.QueryModel, fmt.Sprintf("//field[@name='%s.stream']/@show", proto)); showNode != nil {
		idx, err := strconv.Atoi(showNode.InnerText())
		if err != nil {
			log.Warnf("Unexpected %s node innertext value %s", proto, showNode.InnerText())
		} else {
			res = gwutil.SomeInt(idx)
		}
	}
	return res
}
Return None if not TCP
package pdmltree
import (
	"bytes"
	"encoding/xml"
	"fmt"
	"reflect"
	"strconv"
	"strings"
	"github.com/antchfx/xmlquery"
	"github.com/gcla/gowid"
	"github.com/gcla/gowid/gwutil"
	"github.com/gcla/gowid/widgets/tree"
	"github.com/gcla/termshark/v2/widgets/hexdumper2"
	"github.com/pkg/errors"
	log "github.com/sirupsen/logrus"
)
type ExpandedPaths [][]string
type EmptyIterator struct{}
var _ tree.IIterator = EmptyIterator{}
func (e EmptyIterator) Next() bool {
	return false
}
func (e EmptyIterator) Value() tree.IModel {
	panic(errors.New("Should not call"))
}
type Iterator struct {
	tree *Model
	pos  int
}
var _ tree.IIterator = (*Iterator)(nil)
func (p *Iterator) Next() bool {
	p.pos += 1
	return (p.pos - 1) < len(p.tree.Children_)
}
func (p *Iterator) Value() tree.IModel {
	return p.tree.Children_[p.pos-1]
}
type Model struct {
	UiName         string            `xml:"-"`
	Name           string            `xml:"-"`  
	Expanded       bool              `xml:"-"`
	Pos            int               `xml:"-"`
	Size           int               `xml:"-"`
	Show           string            `xml:"-"`
	Hide           bool              `xml:"-"`
	Children_      []*Model          `xml:",any"`
	Content        []byte            `xml:",innerxml"`  
	NodeName       string            `xml:"-"`
	Attrs          map[string]string `xml:"-"`
	QueryModel     *xmlquery.Node    `xml:"-"`
	Parent         *Model            `xml:"-"`
	ExpandedFields *ExpandedPaths    `xml:"-"`
}
var _ tree.IModel = (*Model)(nil)
var _ tree.ICollapsible = (*Model)(nil)
func (n *Model) HexLayers(pos int, includeFirst bool) []hexdumper2.LayerStyler {
	res := make([]hexdumper2.LayerStyler, 0)
	sidx := 1
	if includeFirst {
		sidx = 0
	}
	for _, c := range n.Children_[sidx:] {
		if c.Pos <= pos && pos < c.Pos+c.Size {
			res = append(res, hexdumper2.LayerStyler{
				Start:         c.Pos,
				End:           c.Pos + c.Size,
				ColUnselected: "hex-layer-unselected",
				ColSelected:   "hex-layer-selected",
			})
			for _, c2 := range c.Children_ {
				if c2.Pos <= pos && pos < c2.Pos+c2.Size {
					res = append(res, hexdumper2.LayerStyler{
						Start:         c2.Pos,
						End:           c2.Pos + c2.Size,
						ColUnselected: "hex-field-unselected",
						ColSelected:   "hex-field-selected",
					})
				}
			}
		}
	}
	return res
}
func (n *Model) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	var err error
	n.Attrs = map[string]string{}
	for _, a := range start.Attr {
		n.Attrs[a.Name.Local] = a.Value
		switch a.Name.Local {
		case "pos":
			n.Pos, err = strconv.Atoi(a.Value)
			if err != nil {
				return errors.WithStack(err)
			}
		case "size":
			n.Size, err = strconv.Atoi(a.Value)
			if err != nil {
				return errors.WithStack(err)
			}
		case "showname":
			n.UiName = a.Value
		case "show":
			if n.UiName == "" {
				n.UiName = a.Value
			}
			n.Show = a.Value
		case "hide":
			n.Hide = (a.Value == "yes")
		case "name":
			n.Name = a.Value
		}
	}
	n.NodeName = start.Name.Local
	type pt Model
	res := d.DecodeElement((*pt)(n), &start)
	return res
}
func DecodePacket(data []byte) *Model {  
	d := xml.NewDecoder(bytes.NewReader(data))
	var n Model
	err := d.Decode(&n)
	if err != nil {
		log.Error(err)
		return nil
	}
	tr := n.removeUnneeded()
	n.QueryModel, err = xmlquery.Parse(strings.NewReader(string(data)))
	if err != nil {
		log.Error(err)
	}
	return tr
}
func (p *Model) TCPStreamIndex() gwutil.IntOption {
	return p.streamIndex("tcp")
}
func (p *Model) UDPStreamIndex() gwutil.IntOption {
	return p.streamIndex("udp")
}