github.com/boki/go-xmp@v1.0.1/xmp/xmp_ext.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 "encoding/xml" 19 ) 20 21 // Raw nodes are used to keep custom data models inside a container. This 22 // is used by extension nodes in the Adobe UMC SDK, but may be used in 23 // private models as well. 24 type Extension Node 25 26 func (x *Extension) MarshalXML(e *xml.Encoder, start xml.StartElement) error { 27 return (*Node)(x).MarshalXML(e, start) 28 } 29 30 func (x *Extension) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { 31 return (*Node)(x).UnmarshalXML(d, start) 32 } 33 34 func (x *Extension) IsZero() bool { 35 return (*Node)(x).IsZero() 36 } 37 38 func (x *Extension) FindNodeByName(name string) *Node { 39 for _, n := range x.Nodes { 40 if n.Name() == name { 41 return n 42 } 43 if n.Model != nil && n.Model.Can(name) { 44 return n 45 } 46 } 47 return nil 48 } 49 50 func (x Extension) MarshalXMP(e *Encoder, node *Node, m Model) error { 51 for _, ext := range x.Nodes { 52 if ext.Model != nil { 53 if err := e.EncodeElement(ext.Model, node); err != nil { 54 return err 55 } 56 } 57 58 // unwrap one extra layer that we keep for identifying extensions 59 if x.XMLName.Local == "" { 60 for _, child := range ext.Nodes { 61 if child.Model != nil { 62 if err := e.EncodeElement(child.Model, node); err != nil { 63 return err 64 } 65 } else { 66 node.Nodes = append(node.Nodes, copyNode(child)) 67 } 68 } 69 } else { 70 node.Nodes = append(node.Nodes, copyNode(ext)) 71 } 72 } 73 return nil 74 } 75 76 func (x *Extension) UnmarshalXMPAttr(d *Decoder, a Attr) error { 77 return d.decodeAttribute(&x.Nodes, a) 78 } 79 80 func (x *Extension) UnmarshalXMP(d *Decoder, src *Node, m Model) error { 81 for _, v := range src.Attr { 82 if err := d.decodeAttribute(&x.Nodes, v); err != nil { 83 return err 84 } 85 } 86 87 for _, child := range src.Nodes { 88 // recurse if we see a new description element (used in xmpMM:pantry) 89 if child.FullName() == "rdf:Description" { 90 if err := x.UnmarshalXMP(d, child, m); err != nil { 91 return err 92 } 93 continue 94 } 95 if err := d.decodeNode(&x.Nodes, child); err != nil { 96 // when decoding fails, store as raw child node 97 x.Nodes = append(x.Nodes, copyNode(child)) 98 } 99 } 100 return nil 101 } 102 103 // used for xmpMM:Pantry bags 104 // 105 // <xmpMM:Pantry> 106 // <rdf:Bag> 107 // <rdf:li> 108 // <rdf:Description>...</rdf:Description> 109 // </rdf:li> 110 // </rdf:Bag> 111 // </xmpMM:Pantry> 112 // 113 type ExtensionArray []*Extension 114 115 func (x ExtensionArray) Typ() ArrayType { 116 return ArrayTypeUnordered 117 } 118 119 func (x ExtensionArray) MarshalXMP(e *Encoder, node *Node, m Model) error { 120 if len(x) == 0 { 121 return nil 122 } 123 bag := NewNode(xml.Name{Local: "rdf:Bag"}) 124 node.Nodes = append(node.Nodes, bag) 125 for _, v := range x { 126 li := NewNode(xml.Name{Local: "rdf:li"}) 127 elem := NewNode(rdfDescription) 128 li.Nodes = append(li.Nodes, elem) 129 if err := e.EncodeElement(v, elem); err != nil { 130 return err 131 } 132 bag.Nodes = append(bag.Nodes, li) 133 } 134 return nil 135 } 136 137 func (x *ExtensionArray) UnmarshalXMP(d *Decoder, node *Node, m Model) error { 138 return UnmarshalArray(d, node, x.Typ(), x) 139 } 140 141 // Generates the following XMP/JSON structures from an array instead of 142 // xmp:<rdf:Bag> / json:[] 143 // 144 // <iXML:extension> 145 // <PRIVATE-NAME-1 rdf:parseType="Resource"> 146 // <PRIVATE-FIELD/> 147 // </PRIVATE-NAME-1> 148 // <PRIVATE-NAME-2 rdf:parseType="Resource"> 149 // <PRIVATE-FIELD/> 150 // </PRIVATE-NAME-2> 151 // </iXML:extension> 152 // 153 // iXML:extension: { 154 // "PRIVATE-NAME-1": { 155 // "PRIVATE-FIELD": "", 156 // }, 157 // "PRIVATE-NAME-2": { 158 // "PRIVATE-FIELD": "", 159 // } 160 // } 161 // 162 type NamedExtensionArray []*Extension 163 164 func (x NamedExtensionArray) Typ() ArrayType { 165 return ArrayTypeUnordered 166 } 167 168 func (x *NamedExtensionArray) FindNodeByName(name string) *Node { 169 for _, v := range *x { 170 n := (*Node)(v) 171 if n.Name() == name { 172 return n 173 } 174 if n.Model != nil && n.Model.Can(name) { 175 return n 176 } 177 } 178 return nil 179 } 180 181 func (x NamedExtensionArray) MarshalXMP(e *Encoder, node *Node, m Model) error { 182 for _, v := range x { 183 ext := NewNode(NewName(v.XMLName.Local)) 184 ext.AddAttr(rdfResourceAttr) 185 ext.Nodes = append(ext.Nodes, copyNodes(v.Nodes)...) 186 ext.Attr = append(ext.Attr, v.Attr...) 187 node.AddNode(ext) 188 } 189 return nil 190 } 191 192 func (x *NamedExtensionArray) UnmarshalXMP(d *Decoder, node *Node, m Model) error { 193 for _, v := range node.Nodes { 194 v.translate(d) 195 ext := (*Extension)(NewNode(NewName(v.XMLName.Local))) 196 ext.Nodes = append(ext.Nodes, copyNodes(v.Nodes)...) 197 ext.Attr = append(ext.Attr, v.Attr...) 198 *x = append(*x, ext) 199 } 200 return nil 201 }