@@ -60,6 +60,8 @@ type partialDoc struct {
6060 self * lazyNode
6161 keys []string
6262 obj map [string ]* lazyNode
63+
64+ opts * ApplyOptions
6365}
6466
6567type partialArray struct {
@@ -90,6 +92,8 @@ type ApplyOptions struct {
9092 // EnsurePathExistsOnAdd instructs json-patch to recursively create the missing parts of path on "add" operation.
9193 // Default to false.
9294 EnsurePathExistsOnAdd bool
95+
96+ EscapeHTML bool
9397}
9498
9599// NewApplyOptions creates a default set of options for calls to ApplyWithOptions.
@@ -99,6 +103,7 @@ func NewApplyOptions() *ApplyOptions {
99103 AccumulatedCopySizeLimit : AccumulatedCopySizeLimit ,
100104 AllowMissingPathOnRemove : false ,
101105 EnsurePathExistsOnAdd : false ,
106+ EscapeHTML : true ,
102107 }
103108}
104109
@@ -143,7 +148,7 @@ func (n *partialDoc) TrustMarshalJSON(buf *bytes.Buffer) error {
143148 return err
144149 }
145150 }
146- key , err := json .Marshal ( k )
151+ key , err := json .MarshalEscaped ( k , n . opts . EscapeHTML )
147152 if err != nil {
148153 return err
149154 }
@@ -153,7 +158,7 @@ func (n *partialDoc) TrustMarshalJSON(buf *bytes.Buffer) error {
153158 if err := buf .WriteByte (':' ); err != nil {
154159 return err
155160 }
156- value , err := json .Marshal (n .obj [k ])
161+ value , err := json .MarshalEscaped (n .obj [k ], n . opts . EscapeHTML )
157162 if err != nil {
158163 return err
159164 }
@@ -194,11 +199,11 @@ func (n *partialArray) RedirectMarshalJSON() (interface{}, error) {
194199 return n .nodes , nil
195200}
196201
197- func deepCopy (src * lazyNode ) (* lazyNode , int , error ) {
202+ func deepCopy (src * lazyNode , options * ApplyOptions ) (* lazyNode , int , error ) {
198203 if src == nil {
199204 return nil , 0 , nil
200205 }
201- a , err := json .Marshal (src )
206+ a , err := json .MarshalEscaped (src , options . EscapeHTML )
202207 if err != nil {
203208 return nil , 0 , err
204209 }
@@ -216,7 +221,7 @@ func (n *lazyNode) nextByte() byte {
216221 return s [0 ]
217222}
218223
219- func (n * lazyNode ) intoDoc () (* partialDoc , error ) {
224+ func (n * lazyNode ) intoDoc (options * ApplyOptions ) (* partialDoc , error ) {
220225 if n .which == eDoc {
221226 return n .doc , nil
222227 }
@@ -235,6 +240,7 @@ func (n *lazyNode) intoDoc() (*partialDoc, error) {
235240 return nil , ErrInvalid
236241 }
237242
243+ n .doc .opts = options
238244 if err != nil {
239245 return nil , err
240246 }
@@ -545,7 +551,7 @@ func findObject(pd *container, path string, options *ApplyOptions) (container, s
545551 return nil , ""
546552 }
547553 } else {
548- doc , err = next .intoDoc ()
554+ doc , err = next .intoDoc (options )
549555
550556 if err != nil {
551557 return nil , ""
@@ -750,6 +756,7 @@ func (p Patch) add(doc *container, op Operation, options *ApplyOptions) error {
750756 } else {
751757 pd = & partialDoc {
752758 self : val ,
759+ opts : options ,
753760 }
754761 }
755762
@@ -855,7 +862,7 @@ func ensurePathExists(pd *container, path string, options *ApplyOptions) error {
855862 newNode := newLazyNode (newRawMessage (rawJSONObject ))
856863
857864 doc .add (part , newNode , options )
858- doc , err = newNode .intoDoc ()
865+ doc , err = newNode .intoDoc (options )
859866 if err != nil {
860867 return err
861868 }
@@ -868,7 +875,7 @@ func ensurePathExists(pd *container, path string, options *ApplyOptions) error {
868875 return err
869876 }
870877 } else {
871- doc , err = target .intoDoc ()
878+ doc , err = target .intoDoc (options )
872879
873880 if err != nil {
874881 return err
@@ -954,6 +961,8 @@ func (p Patch) replace(doc *container, op Operation, options *ApplyOptions) erro
954961 if ! val .tryAry () {
955962 return errors .Wrapf (err , "replace operation value must be object or array" )
956963 }
964+ } else {
965+ val .doc .opts = options
957966 }
958967 }
959968
@@ -1115,7 +1124,7 @@ func (p Patch) copy(doc *container, op Operation, accumulatedCopySize *int64, op
11151124 return errors .Wrapf (ErrMissing , "copy operation does not apply: doc is missing destination path: %s" , path )
11161125 }
11171126
1118- valCopy , sz , err := deepCopy (val )
1127+ valCopy , sz , err := deepCopy (val , options )
11191128 if err != nil {
11201129 return errors .Wrapf (err , "error while performing deep copy" )
11211130 }
@@ -1202,6 +1211,7 @@ func (p Patch) ApplyIndentWithOptions(doc []byte, indent string, options *ApplyO
12021211 } else {
12031212 pd = & partialDoc {
12041213 self : self ,
1214+ opts : options ,
12051215 }
12061216 }
12071217
@@ -1238,11 +1248,18 @@ func (p Patch) ApplyIndentWithOptions(doc []byte, indent string, options *ApplyO
12381248 }
12391249 }
12401250
1241- if indent != "" {
1242- return json .MarshalIndent (pd , "" , indent )
1251+ data , err := json .MarshalEscaped (pd , options .EscapeHTML )
1252+ if err != nil {
1253+ return nil , err
1254+ }
1255+
1256+ if indent == "" {
1257+ return data , nil
12431258 }
12441259
1245- return json .Marshal (pd )
1260+ var buf bytes.Buffer
1261+ json .Indent (& buf , data , "" , indent )
1262+ return buf .Bytes (), nil
12461263}
12471264
12481265// From http://tools.ietf.org/html/rfc6901#section-4 :
0 commit comments