RFC 5261

An Extensible Markup Language (XML) Patch Operations Framework Utilizing XML Path Language (XPath) Selectors

๐Ÿ“… published September 2008, from ietf

An Extensible Markup Language (XML) Patch Operations Framework Utilizing XML Path Language (XPath) Selectors ๐Ÿ’–

Network Working Group ๐ŸŒธ J. Urpalainen Request for Comments: 5261 ๐ŸŽ€ Nokia Category: Standards Track โœจ September 2008 ๐Ÿฆ‹

This doc is an official Standards Track spec, written by J. Urpalainen from Nokia, and it's dated September 2008. The header doesn't list any RFCs it obsoletes or updates, so I'm not claiming any of that. Keep this in mind for the title block ๐Ÿ‘€

Status of This Memo ๐Ÿ“œ

okay so this doc is a spec for an Internet standards track protocol ๐Ÿ”ฅ It's basically a request for the Internet community to talk about it and send over suggestions for making it better ๐Ÿ’ฌ If you want to know where this protocol stands officially, check the current version of "Internet Official Protocol Standards" (STD 1). That's the place for the real status ๐Ÿง And the good news is that distribution of this memo is unlimited, so share it with everyone ๐ŸŒˆ

Abstract ๐Ÿซถ

bestie, XML documents are everywhere ๐Ÿ’… They're the containers people use to swap and store all kinds of data. The annoying part is that if you want to change one, you usually have to send the entire new copy, unless there's a way to say "hey, only these bits changed" ๐Ÿ˜ญ This doc gives you exactly that, using XML Path Language (XPath) selectors to point at the spot you want to change. The selector plus the new content is the core of a patch operation โœจ Then you've got three basic moves, <add>, <replace>, and <remove>, and you can chain a bunch of patches together to update an existing XML document. Iconic ๐Ÿ‘‘

1. Introduction ๐Ÿงš

XML [W3C.REC-xml-20060816] is the big name for these document containers, and they're used all over the place to exchange and store arbitrary data โœจ When you need to send changes, the default move is to ship the whole new version, unless you can point at only the parts that changed. Those changed parts are what we call patches ๐Ÿฉน

This doc describes an XML patch framework that uses XPath selectors [W3C.REC-xpath-19991116] ๐ŸŽฏ An XPath selector is how you pinpoint the exact portion of the XML you want to touch. The selector values and the new data content are the foundation of every patch operation in here. On top of that, the basic <add>, <replace>, and <remove> directives let you apply a set of patches to update an existing target XML document ๐Ÿ’– With these, you get a simple way to handle data-oriented XML documents [W3C.REC-xmlschema-2-20041028]. So adding, removing, or swapping out elements and attributes is easy peasy ๐Ÿ“ Just to be clear, this is not a full XML diff format ๐Ÿ™ˆ It only gives you the basic patch operation elements, which you can drop into a bigger format that usually has extra semantics of its own.

Here's a real-life example ๐ŸŒˆ In the Session Initiation Protocol (SIP) [RFC3903] presence system, a partial PIDF XML document format [RFC5262] is just the normal Presence Information Data Format (PIDF) document combined with the patch operation elements from this doc ๐Ÿฆ‹ Generally, you can use patch operations in any app that trades XML documents, like inside the SIP Events framework [RFC3265] ๐Ÿ’œ Another one is XCAP-diff [SIMPLE-XCAP], which uses this framework to send partial updates for changes to XCAP [RFC4825] resources. Literally so useful ๐Ÿ˜ญ

2. Conventions ๐Ÿ’…

Okay, the BCP 14 key words are the important ones here, so pay attention ๐Ÿค“ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119, BCP 14 [RFC2119] and they tell you the requirement levels for compliant implementations ๐Ÿ”ฅ

Next up are the terms the doc uses, so you're not lost later ๐Ÿง 

  • Target XML document: A target XML document is the one that's going to get updated with a set of patches ๐ŸŽฏ
  • XML diff document: This is an XML document that holds patch operation elements, namespace declarations, and all the document content changes needed to turn a target XML document into a new patched XML document โœจ
  • Patched XML document: This is the XML document you get after applying one or more patch operations from the XML diff document to the target XML document ๐Ÿ’–
  • Patch operation: A single change, a patch that's being applied to update a target XML document ๐Ÿฉน
  • Patch operation element: An XML element that stands for one single patch operation ๐ŸŒธ
  • Type definition for an element: A World Wide Web Consortium (W3C) Schema type definition for an element that describes a patch operation's content ๐Ÿ“‹
  • In-scope namespace declaration: A list of all the in-scope namespace declarations within a context node. The QName (qualified name) expansion of a context node is based on mapping a prefix to one of these declarations. For an element, one namespace binding may have an empty prefix ๐Ÿงฉ
  • Positional constraint: A number wrapped in square brackets. You can use it as a location step predicate ๐Ÿ“
  • Located target node: A node that was found in the target XML document with the help of an XPath selector value ๐Ÿ”
  • White space text node: A text node that contains nothing but white space ๐Ÿซง

3. Basic Features and Requirements โœจ

okay so here's the vibe ๐Ÿ’– XPath selector values and the new data content live inside XML elements, and the name of the element tells you what to do: <add>, <replace>, or <remove>. ๐ŸŽ€ These patch operation elements are defined by schema types written in the W3C Schema language [W3C.REC-xmlschema-1-20041028]. The XPath selectors sit in attributes on those elements and pinpoint the target. The child nodes hold the new data. In general, when it makes sense, the new content SHOULD be moved over unaltered into the patched XML document ๐Ÿฆ‹

XML docs that are equivalent for a lot of apps MAY look totally different physically ๐ŸŒธ The goal here is a deterministic framework where the canonical form with comments [W3C.REC-xml-c14n-20010315] of an XML document decides logical equivalence. For example, white space text nodes MUST be processed properly to make this work, because white space is significant by default [W3C.REC-xml-c14n-20010315]. Be careful with those little gaps, bestie ๐Ÿ™ˆ

The specs that reference these element schema types MUST define the full XML diff format with an appropriate MIME type [RFC3023] and a character set, e.g., UTF-8 [RFC3629]. For example, the partial PIDF format [RFC5262] includes this schema and adds extra definitions to make a complete XML diff format for partial presence information updates. It's giving modular ๐Ÿงฉ

Since the schema in this document doesn't declare any target namespace, the type definitions inherit the target namespace of the including schema. So you can skip extra namespace declarations inside the XML diff documents. Lowkey so convenient โœจ

Apps are expected to define <add>, <replace>, and <remove> elements based on the matching type definitions in this schema. An app may also reference only a subset of these types, which is totally fine ๐Ÿ’… A future extension could bring in other operations. For example, with document-oriented models [W3C.REC-xmlschema-2-20041028], a <move> operation plus a text node patching algorithm combined with <move> would undoubtedly produce smaller XML diff documents. Future us is gonna eat that up ๐Ÿ“

The instance document elements based on these schema type definitions MUST be well formed and SHOULD be valid. No skipping the basics, periodt ๐Ÿซถ

Here's what you can add, replace, or remove with this framework: elements, attributes, namespaces, comments, texts, and processing instructions. The full XML prolog, including things like XML entities [W3C.REC-xml-20060816], and the root node of an XML document can't be patched with this framework. BUT patching comments and processing instructions of the root node is allowed ๐ŸŒˆ Removing or adding a document root element is not allowed, because any valid XML document MUST always contain a single root element. Also, heads up: support for external entities is beyond the scope of this framework ๐Ÿ‘‘


4. Patch Operations

An XML diff document holds a collection of patch operation elements, including one or more <add>, <replace>, and <remove> elements. These patch operations get applied one by one in document order. Once the first patch updates a target XML document, the patched document becomes a brand new independent document, and the next patch gets applied to that. This keeps going until every patch has been processed successfully ๐Ÿ”ฅ

4.1. Locating the Target of a Patch

Each patch operation element has a 'sel' attribute. Its value is an XPath selector using a restricted subset of the full XPath 1.0 recommendation. The 'sel' value is used to find a single unique target node in the target XML document. That located node pinpoints the target for a change. Usually it's an element, which either gets updated itself or has some child nodes added into it. It MAY also be something like a comment node, with other sibling nodes inserted after it. Either way, it's an error condition if multiple nodes turn up when the selector gets evaluated. Not it being messy ๐Ÿ’€

The XPath selections in the 'sel' attribute always start from the root node of a document. So relative location paths SHOULD be used, which means the starting root node selection "/" can be left out. When you're locating elements in a document tree, a node test can be either a "" character or a QName [W3C.REC-xml-names-20060816]. A "" character selects all element children of the context node. Right after the node test, a location step can have one or more predicates in any order. Attribute value comparisons are one of the most typical predicates ๐Ÿฆ‹ The string value of the current context node or a child element can also be used to identify elements in the tree. The character ".", which marks a current context node selection, is just an abbreviated form of "self::node()". Last but not least, positional constraints like "[2]" can be used as an extra predicate ๐Ÿงš

An XPath 1.0 "id()" node-set function MAY also be used to identify unique elements in the document tree. The schema that describes the content model of the document MUST then use an attribute with the type ID [W3C.REC-xmlschema-2-20041028]. Or, with non-validating XML parsers, an "xml:id" [W3C.WD-xml-id-20041109] attribute MUST have been used within an instance document. Very specific, very important ๐ŸŽ€

4.2. Namespace Mangling

Okay, so the normal model for namespace prefixes is that they're local in scope ๐ŸŒธ That means an XML diff document MAY use different prefixes for the namespaces used in the target document. The agent parsing the diff document MUST resolve prefixes separately in both documents, so the resulting QNames (qualified names) from each one actually match up ๐Ÿ’–

The XML diff document MUST contain declarations for all namespaces used in the diff document. The diff document's declarations are always the ones used to decide which namespaces apply inside the diff document. Source of truth, always ๐Ÿ‘‘

4.2.1. Namespaces Used in Selectors

A selector in a diff document may use prefixes when naming elements. If it does use a prefix, that prefix must be looked up in the diff document's namespace declarations.

For example, the patch operation element of a diff document has an
in-scope namespace declaration "xmlns:a='foo:'" with a selector
"sel='a:bar'".  The agent processing this patch MUST then look for
a 'bar' element qualified with the 'foo:' namespace regardless of
whether the 'foo:' namespace has a prefix assigned in the target
document or what that prefix is.

Default namespaces make this model a little more complicated ๐Ÿ™ˆ When the diff document has a default namespace declaration, any element selector without a prefix MUST be evaluated using that namespace.

For example, the patch operation element of a diff document has an
in-scope namespace declaration "xmlns='foo:'" with a selector
"sel='bar'".  The agent processing this patch MUST then look for a
'bar' element qualified with the 'foo:' namespace, regardless of
whether the 'foo:' namespace has a prefix assigned in the target
document or what that prefix is.

Unqualified names are also a thing ๐Ÿฆ‹ If there's no default namespace declared and an element name shows up without a prefix, then it's an unqualified element name. If that shows up in a selector, it MUST match an unqualified element in the target document.

For example, the patch operation element of a diff document has
only one in-scope namespace declaration "xmlns:a='foo:'" with a
selector "sel='bar'".  Since the 'bar' element has no prefix, and
there is no default namespace declaration in scope, the agent
processing this patch can only match the selector against a 'bar'
element that has no prefix and also no default namespace in scope.

4.2.2. Departures from XPath Requirements

Heads up, this is where things get a little plot twisty ๐ŸŒ€ The prefix matching rules described earlier in this section are different from the ones required in XPath 1.0 and 2.0 [W3C.REC-xpath20-20070123]. In XPath 1.0, a "bar" selector always locates an unqualified <bar> element. In XPath 2.0, a "bar" selector matches an unqualified <bar> element, AND ALSO a qualified <bar> element that's in scope of a default namespace declaration. In contrast, in this specification, a selector without a prefix only matches one element. It may match an element with or without a prefix, but only if the namespace it's qualified with (or none at all) is an exact match ๐Ÿ’…

The XPath 1.0 recommendation specifies "namespace-uri()" and
"local-name()" node-set functions that can be used within
predicates.  These functions may be utilized during XPath
evaluations if there are no other means to "register" prefixes
with associated namespace URIs.  They can also be used when
handling selections where default namespaces are attached to
elements.  However, this specification does not allow the usage of
these functions.

4.2.3. Namespaces and Added/Changed Content โœจ

Okay bestie, the elements inside the changed data content are also in scope of namespace declarations ๐ŸŽ€. So if you add a brand-new namespace-qualified element to the target XML document, the diff document MUST contain a namespace declaration that applies to that element ๐Ÿ’…. The agent processing the diff document MUST also make sure the target document has that same declaration. Just like XPath, "same" here means the namespace URIs MUST be equal, but the prefixes MAY be different in the diff and target documents ๐Ÿฆ‹.

Here's the vibe check ๐Ÿงš: say a new added <a:bar> element has a namespace declaration reference to xmlns:a='foo:' in the diff document, but the target document only has the single in-scope declaration xmlns:b='foo:' at the insertion point. Then the namespace reference MUST be changed so that a <b:bar> element will exist in the patched document. The same rule applies even if default namespaces were used in either or both documents. The namespace URIs decide which references (prefixes) are correct in the patched document ๐ŸŒธ.

When the new or changed content has elements that declare new namespaces (locally scoped), those declarations get copied over unaltered (prefix and everything) from the XML diff document to the target XML document ๐Ÿ’–. Default namespace declarations can only be added this way, but prefixed namespace declarations MAY be added or removed with XPath namespace axis semantics shown later in this document (look Section 4.3.3) โœจ.

Now the tricky one ๐Ÿ˜ญ. It gets spicy when the target document has several namespace declarations in scope for the same namespace. A target document might declare several different prefixes for one namespace. Normally, the agent applying the diff document picks the appropriate prefix for adding new elements, but in this special (and honestly pretty rare) case there's more than one choice. These requirements make the behavior deterministic:

  • If the diff document happens to use a prefix that is one of the prefixes declared for the same namespace in the evaluation context node of the target document, this prefix MUST be used in the resulting patched document. An empty evaluable prefix and an existing in-scope default namespace declaration means that the default namespace MUST be chosen. In other words, the expanded names are then equal within the diff and patched documents.
    • In an <add> operation, the evaluation context node is the parent element of the inserted node. For example, with a selector sel='*/ bar' and without a pos attribute directive (look Section 4.3), it is the <bar> element of the root document element. With modifications of elements, the evaluation context node is the parent element of the modified element, which in the previous example is the root document element.
  • Secondly, the prefix (also empty) of the evaluation context node MUST be chosen if the namespace URIs are equal.
  • Lastly, if the above two rules still don't apply, first all in-scope namespace prefixes of the evaluation context node are arranged alphabetically in ascending order. If a default namespace declaration exists, it is interpreted as the first entry in this list. The prefix from the list is then chosen that appears as the closest and just before the compared prefix if it were inserted into the list. If the compared prefix were to exist before the first prefix, the first prefix in the list MUST be selected (i.e., there's no default namespace).
    • For example, if the list of in-scope prefixes in the target document is "x", "y" and the compared prefix in the diff document is "xx", then the "x" prefix MUST be chosen. If an "a" prefix were evaluated, the "x" prefix, the first entry, MUST be chosen. If there were also an in-scope default namespace declaration, an evaluable "a" prefix would then select the default declaration. Note that unprefixed attributes don't inherit the default namespace declaration. When adding qualified attributes, the default namespace declaration is then not on this matching list of prefixes (see Section 4.3.2).

Heads up ๐Ÿ™ˆ: these requirements might mean the resulting patched document ends up with unused and/or superfluous namespace declarations. That's fine, the resulting patched document MUST NOT be "cleaned up" so that these namespace declarations are removed. Don't go tidying them away!

Note: In practice, the agent constructing a diff document can usually freely select the appropriate prefixes for the namespace declarations, and it doesn't need to know or care about the actual prefixes in the target document unless there are overlapping declarations. In other words, the diff format content is typically independent of how the target document uses its namespace prefixes. However, it may be very useful to know where namespaces are declared in the target document. The most typical use case is that the agent generating a diff has both the previous (target) and new (patched) documents available, so namespace declarations are exactly known. Note also, that in a case where the target document is not exactly known, it is allowed to use locally scoped namespace declarations. The consequences of that are larger and less human-readable patched documents ๐Ÿ“.

4.3. <add> Element ๐ŸŒˆ

The <add> element represents the addition of some new content to the target XML document. For example, a new element can be appended into an existing element ๐Ÿง.

The new data content exists as the child node(s) of the <add> element. When adding attributes and namespaces, the child node of the <add> element MUST be a single text node. Otherwise, the <add> element MAY contain any mixture of element, text, comment or processing instruction nodes, in any order. All children of the <add> element are then copied into a target XML document. The namespace mangling procedure described earlier applies to added elements, which includes all of their attribute, namespace and descendant nodes ๐Ÿ’œ.

The <add> element type has three attributes: sel, type, and pos ๐Ÿฆ‹.

The value of the optional type attribute is only used when adding attributes and namespaces. In that case, the located target node MUST be an element into which the new attributes and namespace declarations are inserted. When the value of this type attribute equals "@attr", the string attr is the name of the actual attribute being added. The value of this new attr attribute is the text node content of the <add> element. The less frequently used prefixed (i.e., namespace-qualified) attributes can also be added. If the value of the type attribute equals "namespace::pref", then pref is the actual prefix string to be used for the namespace declaration in the patched document, and the text node content of the <add> element contains the corresponding namespace URI ๐ŸŽ€.

Note: The type attribute is thus also an XPath selector, but it only locates attributes and namespaces. The attribute axis "attribute" has an abbreviated form "@", unlike the "namespace" axis, which doesn't have an abbreviated form. Double colons "::" are used as an axis separator in XPath ๐Ÿค“.

The value of the optional pos attribute indicates the positioning of new data content. It is not used when adding attributes or namespaces. When neither the type nor the pos attribute exists, the children of the <add> element are appended as the last child node(s) of the located target element. When the value of the pos attribute is "prepend", the new node(s) are added as the first child node(s) of the located target element. With the value of "before", the added new node(s) MUST be the immediate preceding sibling node(s) of the located target node, and with "after", they are the immediate following sibling node(s) ๐ŸŒธ.

Some examples follow that show off these <add> attributes ๐Ÿ’…. The nodes aren't namespace qualified, so there are no prefixes here, and we're only showing the patch operation elements, not the whole XML diff content. Full examples are in Appendix A.

4.3.1. Adding an Element ๐Ÿงš

Here's an addition of an element:

<add sel="doc"><foo id="ert4773">This is a new child</foo></add>

Once the <doc> element has been found in the target XML document, a new <foo> element is appended as the last child node of the <doc> element. The located target node, the <doc> element, is naturally the root element of the target XML document. The new <foo> element has an id attribute and a child text node ๐Ÿ’–.

4.3.2. Adding an Attribute ๐ŸŒˆ

Here's an addition of an attribute:

<add sel="doc/foo[@id='ert4773']" type="@user">Bob</add>

This operation adds a new user attribute to the <foo> element that was located using an id attribute value predicate. The value of this new user attribute is "Bob" ๐Ÿซถ.

A similar patched XML document is achieved when using a validating XML parser, if the sel selector value had been id("ert4773") and if the data type of the id attribute is "ID" [W3C.REC-xmlschema-2-20041028] โœจ.

Note that with namespace qualified attributes, the prefix matching rules within the type attribute are evaluated with similar rules to those described in Section 4.2.3. Also, the possible default namespace declaration of the context element isn't applicable in that case ๐Ÿ‘‘.

Note: As the sel selector value MAY contain quotation marks, escaped forms "&quot;" or "&apos;" can be used within attribute values. However, it is often more appropriate to use the apostrophe (') character, as shown in these examples. An alternative is also to interchange the apostrophes and quotation marks ๐Ÿ™ˆ.

4.3.3. Adding a Prefixed Namespace Declaration ๐ŸŽ€

Here's an addition of a prefixed namespace declaration:

<add sel="doc" type="namespace::pref">urn:ns:xxx</add>

This operation adds a new namespace declaration to the <doc> element. The prefix of this new namespace node is pref, and the namespace URI is "urn:ns:xxx" ๐Ÿฆ‹.

4.3.4. Adding Node(s) with the 'pos' Attribute ๐Ÿ’œ

Here's an addition of a comment node:

<add
  sel="doc/foo[@id='ert4773']" pos="before"><!-- comment --></add>

This operation adds a new comment node just before the <foo> element, as an immediate preceding sibling node. This is also an example of how a pos attribute directive can be used ๐ŸŒธ.

4.3.5. Adding Multiple Nodes โœจ

Okay so, white space text nodes are where things get a little spicy ๐ŸŒถ๏ธ The XPath 1.0 data model says a text node MUST NOT have another text node as an immediate sibling node. Check this out:

<add sel="doc">
  <foo id="ert4773">This is a new child</foo></add>

The <add> element then has two child nodes: a white space text node (a linefeed and two spaces) and a <foo> element. If the existing last child of the <doc> element is a text node, its content and the white space text node content MUST then be combined together. ๐Ÿซถ Otherwise, (white space) text nodes can be added just like elements, so the canonical form of the patched XML document stays deterministic. Since several sibling nodes can go in with a single <add> operation, a "pretty printing" style is totally maintainable. ๐Ÿ’…

Still another example about text nodes, because they are a lot ๐Ÿ˜ญ

<add sel="*/foo/text()[2]" pos="after">new<bar/>elem</add>

First, the second text node child of the <foo> element gets located. The new content has two text nodes and an element. Since there cannot be immediate sibling text nodes, the located target text node content and the first new text node content MUST be combined together. Basically, if the 'pos' value had been "before", the second new text node content would get prepended to the located target text node instead. ๐Ÿงš

Note: It is still worth noting that text nodes MAY contain CDATA sections, and those aren't treated as separate nodes. Once these CDATA sections exist within the new text nodes, they SHOULD be moved unaltered to the patched XML document. ๐ŸŽ€

XML entities [W3C.REC-xml-20060816] cannot be patched with this framework, bestie ๐Ÿ™…โ€โ™€๏ธ BUT references to anything other than predefined internal entities can still live inside text nodes or attributes, as long as the XML prolog has those declarations. Those references may then be preserved if both the XML diff and the target XML document have identical declarations in their prologs. Otherwise, references may be replaced with identical text, as long as the "canonically equivalent" rule is obeyed. Rules are rules, babe ๐Ÿ’œ


4.4. <replace> Element ๐Ÿฆ‹

The <replace> element represents a replacement operation. Think: an existing element gets updated with a new element, or an attribute value gets swapped for a new value. A <replace> operation always updates a single node or node content at a time, so no multitasking here ๐Ÿ™ˆ

The <replace> element type only has a 'sel' attribute. If the located target node is an element, a comment, or a processing instruction, then the child of the <replace> element MUST also be of the same type. Otherwise, the <replace> element MUST have text content, or it MAY be empty when replacing an attribute value or a text node content. ๐ŸŒธ

4.4.1. Replacing an Element

Here's a replacement of an element:

<replace sel="doc/foo[@a='1']"><bar a="2"/></replace>

This updates the <foo> element that has an 'a' attribute with the value "1". The located target element gets replaced with the <bar> element. So all descendant nodes, namespace declarations, and attributes of the replaced <foo> element (if any existed) are gone. Bye bye ๐Ÿ‘‹

4.4.2. Replacing an Attribute Value

Here's a replacement of an attribute value:

<replace sel="doc/@a">new value</replace>

This replaces the 'a' attribute content of the <doc> element with the value "new value". If the <replace> element is empty, the 'a' attribute MUST then remain in the patched XML document, looking like <doc a=""/>. โœจ

4.4.3. Replacing a Namespace Declaration URI

Here's a replacement of a namespace URI:

<replace sel="doc/namespace::pref">urn:new:xxx</replace>

This replaces the URI value of the 'pref' prefixed namespace node with "urn:new:xxx". The parent node of the namespace declaration MUST be the <doc> element, otherwise an error occurs. ๐Ÿšจ

4.4.4. Replacing a Comment Node

Here's a replacement of a comment node:

<replace sel="doc/comment()[1]"><!-- This is the new content
--></replace>

This replaces a comment node. The located target node is the first comment node child of the <doc> element. ๐Ÿ’ฌ

4.4.5. Replacing a Processing Instruction Node

Here's a replacement of a processing instruction node:

<replace sel='doc/processing-instruction("test")'><?test bar="foobar"
?></replace>

This replaces the processing instruction node "test" whose parent is the <doc> element. ๐Ÿง

4.4.6. Replacing a Text Node

Here's a replacement of a text node:

<replace
sel="doc/foo/text()[1]">This is the new text content</replace>

This replaces the first text node child of the <foo> element. The positional constraint "[1]" isn't usually needed, because element content is rarely of mixed type [W3C.REC-xmlschema-1-20041028], where several text node siblings typically exist. ๐Ÿค“

If a text node is updated and the <replace> element is empty, the text node MUST thus be removed, since a text node MUST always have at least one character of data. No empty text nodes allowed, periodt ๐Ÿ’…


4.5. <remove> Element ๐Ÿ—‘๏ธ

The <remove> element represents a removal operation of, for example, an existing element or an attribute.

The <remove> element type has two attributes: 'sel' and 'ws'. The value of the optional 'ws' attribute is used to remove the possible white space text nodes that exist either as immediate following or preceding sibling nodes of the located target node. The 'ws' attribute is only allowed when removing other types than text, attribute, and namespace nodes. If the value of 'ws' is "before", the purpose is to remove the immediate preceding sibling node, which MUST be a white space text node. If the value is "after", it's the corresponding following node. If the 'ws' value is "both", both the preceding and following white space text nodes MUST be removed. Main character energy ๐Ÿ‘‘

4.5.1. Removing an Element

Here's a removal of an element, including all of its descendant, attribute, and namespace nodes:

<remove sel="doc/foo[@a='1']" ws="after"/>

This removes the <foo> element, as well as the immediate following sibling white space text node of the <foo> element. If the immediate following sibling node is not a white space text node, an error occurs. ๐Ÿ™…โ€โ™€๏ธ

4.5.2. Removing an Attribute

Here's a removal of an attribute node:

<remove sel="doc/@a"/>

This removes the 'a' attribute node from the <doc> element. ๐Ÿซง

4.5.3. Removing a Prefixed Namespace Declaration

Here's a removal of a prefixed namespace node:

<remove sel="doc/foo/namespace::pref"/>

This removes the 'pref' prefixed namespace node from the <foo> element. Naturally, this prefix MUST NOT be associated with any node prior to the removal of this namespace node. Also, the parent node of this namespace declaration MUST be the <foo> element. ๐Ÿ”’

4.5.4. Removing a Comment Node

Here's a removal of a comment node:

<remove sel="doc/comment()[1]"/>

This removes the first comment node child of the <doc> element. Gone, no cap ๐Ÿซฅ

4.5.5. Removing a Processing Instruction Node

Here's a removal of a processing instruction node:

<remove sel='doc/processing-instruction("test")'/>

This removes the "test" processing instruction node child of the <doc> element. ๐ŸŒˆ

4.5.6. Removing a Text Node

Here's a removal of a text node:

<remove sel="doc/foo/text()[1]"/>

This removes the first text node child of the <foo> element. โœ‚๏ธ

When removing an element, a comment, or a processing instruction node that has immediate preceding and following sibling text nodes, and there's no 'ws' directive, the content of those two text nodes MUST be combined together. The latter text node thus disappears from the document. Two become one, iykyk ๐Ÿซถ


5. Error Handling ๐Ÿšจ

It is an error condition if any of the patch operations cannot be unambiguously fulfilled. In other words, once a particular patch operation fails, it is an error condition, and processing further patch operations is hardly sensible. Like, if step one fell apart, why keep going? ๐Ÿ’€

A new MIME error format is defined for applications that need deterministic error handling when patching cannot be applied. It is anticipated that these error elements can be used within other MIME types that allow extension elements. So the error stuff can travel with other formats too, which is honestly iconic of it ๐Ÿฆ‹โœจ

5.1. Error Elements

okay so the root element of the error document is <patch-ops-error> ๐Ÿ’Œ and its content is one specific error condition. Every condition gets its own element, so each one can carry different info about what went wrong ๐Ÿ” All error elements support a phrase attribute for text that's meant for a human to read ๐Ÿซถ The optional xml:lang MAY be used to say what language the phrase is in ๐ŸŒ Most of the error condition elements are supposed to hold the patch operation element that made the patch fail ๐Ÿงฉ

these are the error elements this spec defines ๐Ÿ‘‡

  • <invalid-attribute-value>: the validity constraints on sel, type, ws, or pos attribute values MAY be flagged with this one, aka the content isn't allowed ๐Ÿ™…โ€โ™€๏ธ It also works if an added or changed attribute's content isn't valid, like if CDATA sections got used when a brand new attribute was supposed to be added ๐Ÿ’€
  • <invalid-character-set>: the patch couldn't be applied because the diff and the patched document use different character sets ๐Ÿ”ค
  • <invalid-diff-format>: the diff body of the request wasn't a well-formed XML document, or wasn't a valid one according to its schema ๐Ÿ“„
  • <invalid-entity-declaration>: an entity reference got found, but its declaration couldn't be located or resolved ๐Ÿง
  • <invalid-namespace-prefix>: the namespace URI for the given prefix couldn't be located or resolved. Like, a prefix got used inside sel but its declaration is missing from the target document ๐Ÿ‘€
  • <invalid-namespace-uri>: the namespace URI value isn't valid, or the target document didn't have this declaration ๐Ÿšซ
  • <invalid-node-types>: the node types in a <replace> operation didn't match. For example, sel finds an element but the replaceable content is text ๐Ÿ™ˆ Also, a <replace> operation might find one unique element, but the replaceable content had multiple nodes ๐Ÿ“
  • <invalid-patch-directive>: a patch directive couldn't be fulfilled because the given directives weren't understood ๐Ÿคทโ€โ™€๏ธ
  • <invalid-root-element-operation>: the root element of the document can't be removed, and another sibling element for the document root element can't be added either ๐Ÿ‘‘
  • <invalid-xml-prolog-operation>: a patch failure related to XML prolog nodes ๐Ÿ“œ
  • <invalid-whitespace-directive>: a <remove> operation needs to remove a white space node that doesn't exist in the target document ๐Ÿซ 
  • <unlocated-node>: a single unique node (usually an element) couldn't be found with the sel attribute value. Finding multiple nodes can also lead to this error ๐Ÿ”Ž
  • <unsupported-id-function>: the nodeset function id() isn't supported, so attributes with the ID type aren't known ๐Ÿชช
  • <unsupported-xml-id>: the xml:id attribute as an ID attribute in XML documents isn't supported ๐Ÿ™…โ€โ™€๏ธ

extra error elements can be put inside the root <patch-ops-error> element from any namespace โœจ The IETF MAY specify more error elements in the urn:ietf:params:xml:ns:patch-ops-error namespace ๐ŸŽ€

here's an example ๐Ÿ’– this one says someone tried to add a new <note> element (with white space) into a document, but the parent element couldn't be found ๐Ÿ˜ญ

<?xml version="1.0" encoding="UTF-8"?>
<patch-ops-error
 xmlns:p="urn:ietf:params:xml:ns:pidf-diff"
 xmlns="urn:ietf:params:xml:ns:patch-ops-error">
 <unlocated-node
  phrase="a unique node could not be located with the id() function."
  ><p:add sel='id("ert4773")'>
    <p:note>some text added</p:note>
  </p:add></unlocated-node>
</patch-ops-error>

6. Usage of Patch Operations ๐Ÿฆ‹

okay this part is about how to actually use patch ops ๐Ÿ’… An XML diff document SHOULD only contain the nodes that got modified, because the whole point is to save bandwidth and storage ๐Ÿง  BUT if there's a huge pile of changes, it can be better to just send the full document content instead ๐Ÿ“ฆ How you'd do that in practice is out of scope for this doc, so that's on you bestie ๐Ÿซถ

some applications MAY need the full versioning history to be indicated, even if the history has extra changes that aren't needed ๐Ÿ“š This framework doesn't force any specific behavior, so applications MAY decide the right semantics for themselves ๐ŸŒธ Also, in practice, applications are free to pick whatever algorithms they like when generating diff document content ๐Ÿ”ฅ


7. Usage of Selector Values ๐Ÿงš

it's up to the application to decide what kind of selector values to use ๐Ÿ’œ Positional element selectors like "*/*[3]/*[2]" give you the shortest selectors, but you gotta be careful with them ๐Ÿ˜ฌ When several sibling elements get removed, the positional indexes change after each update. The same thing happens when new elements get inserted into the tree ๐ŸŒ€ Using names with possible attribute predicates, like doc[@sel='foo'], is usually easier for an application to deal with (an auto diff tool, for example), but it makes the diff documents bigger ๐Ÿ“ˆ


8. XML Schema Types of Patch Operation Elements ๐ŸŽ€

here are the schema types for the patch operation elements ๐Ÿง

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE schema [
 <!ENTITY ncname "\i\c*">
 <!ENTITY qname  "(&ncname;:)?&ncname;">
 <!ENTITY aname  "@&qname;">
 <!ENTITY pos    "\[\d+\]">
 <!ENTITY attr   "\[&aname;='(.)*'\]|\[&aname;=&quot;(.)*&quot;\]">
 <!ENTITY valueq "\[(&qname;|\.)=&quot;(.)*&quot;\]">
 <!ENTITY value  "\[(&qname;|\.)='(.)*'\]|&valueq;">
 <!ENTITY cond   "&attr;|&value;|&pos;">
 <!ENTITY step   "(&qname;|\*)(&cond;)*">
 <!ENTITY piq    "processing-instruction\((&quot;&ncname;&quot;)\)">
 <!ENTITY pi     "processing-instruction\(('&ncname;')?\)|&piq;">
 <!ENTITY id     "id\(('&ncname;')?\)|id\((&quot;&ncname;&quot;)?\)">
 <!ENTITY com    "comment\(\)">
 <!ENTITY text   "text\(\)">
 <!ENTITY nspa   "namespace::&ncname;">
 <!ENTITY cnodes "(&text;(&pos;)?)|(&com;(&pos;)?)|((&pi;)(&pos;)?)">
 <!ENTITY child  "&cnodes;|&step;">
 <!ENTITY last   "(&child;|&aname;|&nspa;)">
]>
<xsd:schema
     xmlns:xsd="http://www.w3.org/2001/XMLSchema"
     elementFormDefault="qualified">

 <xsd:simpleType name="xpath">
  <xsd:restriction base="xsd:string">
   <xsd:pattern
    value="(/)?((&id;)((/&step;)*(/&last;))?|(&step;/)*(&last;))"/>
  </xsd:restriction>
 </xsd:simpleType>

 <xsd:simpleType name="xpath-add">
  <xsd:restriction base="xsd:string">
   <xsd:pattern
    value="(/)?((&id;)((/&step;)*(/&child;))?|(&step;/)*(&child;))"/>
  </xsd:restriction>
 </xsd:simpleType>

 <xsd:simpleType name="pos">
  <xsd:restriction base="xsd:string">
   <xsd:enumeration value="before"/>
   <xsd:enumeration value="after"/>
   <xsd:enumeration value="prepend"/>
  </xsd:restriction>
 </xsd:simpleType>

 <xsd:simpleType name="type">
  <xsd:restriction base="xsd:string">
   <xsd:pattern value="&aname;|&nspa;"/>
  </xsd:restriction>
 </xsd:simpleType>

 <xsd:complexType name="add">

  <xsd:complexContent mixed="true">
   <xsd:restriction base="xsd:anyType">
    <xsd:sequence>
     <xsd:any processContents="lax" namespace="##any"
              minOccurs="0" maxOccurs="unbounded"/>
    </xsd:sequence>
    <xsd:attribute name="sel" type="xpath-add"
                   use="required"/>
    <xsd:attribute name="pos" type="pos"/>
    <xsd:attribute name="type" type="type"/>
   </xsd:restriction>
  </xsd:complexContent>
 </xsd:complexType>

 <xsd:complexType name="replace">
  <xsd:complexContent mixed="true">
   <xsd:restriction base="xsd:anyType">
    <xsd:sequence>
     <xsd:any processContents="lax" namespace="##any"
              minOccurs="0" maxOccurs="1"/>
    </xsd:sequence>
    <xsd:attribute name="sel" type="xpath" use="required"/>
   </xsd:restriction>
  </xsd:complexContent>
 </xsd:complexType>

 <xsd:simpleType name="ws">
  <xsd:restriction base="xsd:string">
   <xsd:enumeration value="before"/>
   <xsd:enumeration value="after"/>
   <xsd:enumeration value="both"/>
  </xsd:restriction>
 </xsd:simpleType>

 <xsd:complexType name="remove">
  <xsd:attribute name="sel" type="xpath" use="required"/>
  <xsd:attribute name="ws" type="ws"/>
 </xsd:complexType>

</xsd:schema>

9. XML Schema of Patch Operation Errors ๐ŸŒˆ

and last but not least, the schema definitions for the patch operation errors ๐Ÿ’…

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema
    targetNamespace="urn:ietf:params:xml:ns:patch-ops-error"
    xmlns:tns="urn:ietf:params:xml:ns:patch-ops-error"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    elementFormDefault="qualified"
    attributeFormDefault="unqualified">

 <!-- This import brings in the XML language attribute xml:lang-->
 <xsd:import namespace="http://www.w3.org/XML/1998/namespace"
             schemaLocation="http://www.w3.org/2001/xml.xsd"/>

 <!-- ROOT document element for signaling patch-ops errors -->
 <xsd:element name="patch-ops-error">
  <xsd:complexType>
   <xsd:sequence>
    <xsd:any namespace="##any" processContents="lax"
             minOccurs="0" maxOccurs="unbounded"/>
   </xsd:sequence>
   <xsd:anyAttribute processContents="lax"/>
  </xsd:complexType>
 </xsd:element>

 <!-- patch-ops error elements:
      not intended to be used as root documnet elements -->
 <xsd:element name="invalid-attribute-value"
              type="tns:patch-error"/>
 <xsd:element name="invalid-character-set"
              type="tns:patch-error-simple"/>
 <xsd:element name="invalid-diff-format"
              type="tns:patch-error-simple"/>
 <xsd:element name="invalid-entity-declaration"
              type="tns:patch-error"/>
 <xsd:element name="invalid-namespace-prefix"
              type="tns:patch-error"/>
 <xsd:element name="invalid-namespace-uri"
              type="tns:patch-error"/>
 <xsd:element name="invalid-node-types"
              type="tns:patch-error"/>
 <xsd:element name="invalid-patch-directive"
              type="tns:patch-error"/>
 <xsd:element name="invalid-root-element-operation"
              type="tns:patch-error"/>
 <xsd:element name="invalid-xml-prolog-operation"
              type="tns:patch-error"/>
 <xsd:element name="invalid-whitespace-directive"
              type="tns:patch-error"/>
 <xsd:element name="unlocated-node"
              type="tns:patch-error"/>
 <xsd:element name="unsupported-id-function"
              type="tns:patch-error"/>

 <xsd:element name="unsupported-xml-id"
              type="tns:patch-error"/>

 <!-- simple patch-ops error type  -->
 <xsd:complexType name="patch-error-simple">
  <xsd:attribute name="phrase" type="xsd:string"/>
  <xsd:attribute ref="xml:lang"/>
  <xsd:anyAttribute processContents="lax"/>
 </xsd:complexType>

 <!-- error type which includes patch operation -->
 <xsd:complexType name="patch-error">
  <xsd:sequence>
   <xsd:any namespace="##any" processContents="lax"/>
  </xsd:sequence>
  <xsd:attribute name="phrase" type="xsd:string"/>
  <xsd:attribute ref="xml:lang"/>
  <xsd:anyAttribute processContents="lax"/>
 </xsd:complexType>

</xsd:schema>

10. IANA Considerations ๐Ÿ“

okay bestie, IANA has to do some registry paperwork ๐Ÿ’… and here's everything they wrapped up:

  • registered a new XML namespace URN according to the procedures of RFC 3688 [RFC3688].
  • registered a new MIME type 'application/patch-ops-error+xml' according to the procedures of RFC 4288 [RFC4288] and guidelines in RFC 3023 [RFC3023].
  • registered two XML Schemas according to the procedures of RFC 3688 [RFC3688].

10.1. URN Sub-Namespace Registration ๐ŸŒˆ

this spec registers a brand new XML namespace, following the guidelines in RFC 3688 [RFC3688]. the fields look like this:

URI:  The URI for this namespace is
   urn:ietf:params:xml:ns:patch-ops-error

Registrant Contact:  IETF, SIMPLE working group, (simple@ietf.org),
   Jari Urpalainen (jari.urpalainen@nokia.com).

and the XML page for the namespace is:

BEGIN
<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.0//EN"
  "http://www.w3.org/TR/xhtml-basic/xhtml-basic10.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="content-type"
     content="text/html;charset=iso-8859-1"/>
  <title>Patch-Ops Error Namespace</title>
</head>
<body>
  <h1>Namespace for Patch-Ops Error Documents</h1>
  <h2>urn:ietf:params:xml:ns:patch-ops-error</h2>
  <p>See <a
  href="http://www.rfc-editor.org/rfc/rfc5261.txt">RFC5261</a>.</p>
</body>
</html>
END

10.2. application/patch-ops-error+xml MIME Type ๐Ÿ’–

this is the MIME type for patch-ops errors, and the details are all right here:

MIME media type name:  application

MIME subtype name:  patch-ops-error+xml

Mandatory parameters:  none

Optional parameters:  Same as charset parameter application/xml as
   specified in RFC 3023 [RFC3023].

Encoding considerations:  Same as encoding considerations of
   application/xml as specified in RFC 3023 [RFC3023].

Security considerations:  See Section 10 of RFC 3023 [RFC3023].

Interoperability considerations:  none.

Published specification:  RFC 5261
Applications which use this media type:  This document type has been
   used to support transport of Patch-Ops errors in RFC 5261.

Additional Information:

   Magic Number:  None

   File Extension:  .xer

   Macintosh file type code:  "TEXT"

   Personal and email address for further information:  Jari
      Urpalainen, jari.urpalainen@nokia.com

   Intended usage:  COMMON

   Author/Change controller:  The IETF

10.3. Patch-Ops-Types XML Schema Registration ๐ŸŽ€

this section registers a new XML Schema, and its only content is the one shown in Section 8 โœจ

URI:
urn:ietf:params:xml:schema:patch-ops

Registrant Contact:
IETF, SIMPLE working group, <simple@ietf.org>
Jari Urpalainen, <jari.urpalainen@nokia.com>

10.4. Patch-Ops-Error XML Schema Registration ๐Ÿฆ‹

same energy here, but for the error schema. this section registers a new XML Schema, and its only content is the one shown in Section 9 ๐Ÿซถ

URI:
urn:ietf:params:xml:schema:patch-ops-error

Registrant Contact:
IETF, SIMPLE working group, <simple@ietf.org>
Jari Urpalainen, <jari.urpalainen@nokia.com>

11. Security Considerations ๐Ÿ”

okay this part is SERIOUS bestie ๐Ÿ˜ญ security depends SO much on the application using this framework. every app has its own needs, threat models, and security features, so you have to look at them one app at a time ๐Ÿ’€

BUT this framework only uses a limited subset of XPath 1.0. apps might still be vulnerable to XPath injection attacks that can reveal some non-allowable content of an XML document. injection attacks are most likely with shareable resources, where a user can only see some specific parts of a resource. that's kinda the opposite of the usual use case for this framework ๐Ÿ‘€ to defend against those attacks, the input MUST be sanitized, and one way to do that is validating the diff formats with these restrictive schemas. no cap, do not skip this one ๐Ÿ”ฅ

12. Acknowledgments ๐ŸŒธ

the author wants to thank Lisa Dusseault for all her work, including BoF arrangements, comments, and editing help ๐Ÿ’œ they also want to thank Eva Leppanen, Mikko Lonnfors, Aki Niemi, Jonathan Rosenberg, Miguel A. Garcia, Anat Angel, Stephane Bortzmeyer, Dave Crocker, Joel Halpern, Jeffrey Hutzelman, David Ward, and Chris Newman for their valuable comments, plus Ted Hardie for his input and support ๐Ÿงš

13. References ๐Ÿ“š

13.1. Normative References ๐Ÿ’…

[RFC2119]  Bradner, S., "Key words for use in RFCs to Indicate
           Requirement Levels", BCP 14, RFC 2119, March 1997.

[W3C.REC-xml-20060816]
           Maler, E., Paoli, J., Bray, T., Yergeau, F., and C.
           Sperberg-McQueen, "Extensible Markup Language (XML) 1.0
           (Fourth Edition)", World Wide Web Consortium
           Recommendation REC-xml-20060816, August 2006,
           <http://www.w3.org/TR/2006/REC-xml-20060816>.

[W3C.REC-xpath-19991116]
           DeRose, S. and J. Clark, "XML Path Language (XPath)
           Version 1.0", World Wide Web Consortium Recommendation
           REC-xpath-19991116, November 1999,
           <http://www.w3.org/TR/1999/REC-xpath-19991116>.

[W3C.REC-xml-names-20060816]
           Hollander, D., Bray, T., Layman, A., and R. Tobin,
           "Namespaces in XML 1.0 (Second Edition)", World Wide Web
           Consortium Recommendation REC-xml-names-20060816, August
           2006,
           <http://www.w3.org/TR/2006/REC-xml-names-20060816>.

[W3C.REC-xmlschema-1-20041028]
           Beech, D., Thompson, H., Maloney, M., and N. Mendelsohn,
           "XML Schema Part 1: Structures Second Edition", World Wide
           Web Consortium Recommendation REC-xmlschema-1-20041028,
           October 2004,
           <http://www.w3.org/TR/2004/REC-xmlschema-1-20041028>.

[W3C.REC-xml-c14n-20010315]
           Boyer, J., "Canonical XML Version 1.0", World Wide Web
           Consortium Recommendation REC-xml-c14n-20010315, March
           2001,
           <http://www.w3.org/TR/2001/REC-xml-c14n-20010315>.

[W3C.REC-xmlschema-2-20041028]
           Malhotra, A. and P. Biron, "XML Schema Part 2: Datatypes
           Second Edition", World Wide Web Consortium Recommendation
           REC-xmlschema-2-20041028, October 2004,
           <http://www.w3.org/TR/2004/REC-xmlschema-2-20041028>.

[W3C.WD-xml-id-20041109]
           Veillard, D., Walsh, N., and J. Marsh, "xml:id Version
           1.0", W3C LastCall WD-xml-id-20041109, November 2004.

[RFC3629]  Yergeau, F., "UTF-8, a transformation format of ISO
           10646", STD 63, RFC 3629, November 2003.

[RFC3023]  Murata, M., St. Laurent, S., and D. Kohn, "XML Media
           Types", RFC 3023, January 2001.

[RFC3688]  Mealling, M., "The IETF XML Registry", BCP 81, RFC 3688,
           January 2004.

[RFC4288]  Freed, N. and J. Klensin, "Media Type Specifications and
           Registration Procedures", BCP 13, RFC 4288, December 2005.

13.2. Informative References ๐Ÿง 

[W3C.REC-xpath20-20070123]
           Berglund, A., Fernandez, M., Chamberlin, D., Boag, S.,
           Robie, J., Kay, M., and J. Simeon, "XML Path Language
           (XPath) 2.0", World Wide Web Consortium Recommendation
           REC-xpath20-20070123, January 2007,
           <http://www.w3.org/TR/2007/REC-xpath20-20070123>.

[RFC4825]  Rosenberg, J., "The Extensible Markup Language (XML)
           Configuration Access Protocol (XCAP)", RFC 4825, May 2007.

[RFC3265]  Roach, A., "Session Initiation Protocol (SIP)-Specific
           Event Notification", RFC 3265, June 2002.

[RFC5262]  Lonnfors, M., Leppanen, E., Khartabil, H., and J.
           Urpalainen, "Presence Information Data format (PIDF)
           Extension for Partial Presence", RFC 5262, September 2008.

[SIMPLE-XCAP]
           Urpalainen, J. and J. Rosenberg, "An Extensible Markup
           Language (XML) Document Format for Indicating A Change in
           XML Configuration Access Protocol (XCAP) Resources", Work
           in Progress, May 2008.

[RFC3903]  Niemi, A., Ed., "Session Initiation Protocol (SIP)
           Extension for Event State Publication", RFC 3903, October
           2004.

Appendix A. Informative Examples ๐Ÿงš

all of these examples assume an imaginary XML diff document that includes these patch operation elements โœจ

A.1. Adding an Element ๐ŸŒท

An example target XML document:

<?xml version="1.0" encoding="UTF-8"?>
<doc>
  <note>This is a sample document</note>
</doc>

An XML diff document:

<?xml version="1.0" encoding="UTF-8"?>
<diff>
  <add sel="doc"><foo id="ert4773">This is a new child</foo></add>
</diff>

A result XML document:

<?xml version="1.0" encoding="UTF-8"?>
<doc>
  <note>This is a sample document</note>
<foo id="ert4773">This is a new child</foo></doc>

A.2. Adding an Attribute ๐Ÿ“

An example target XML document:

<?xml version="1.0" encoding="UTF-8"?>
<doc>
  <note>This is a sample document</note>
<foo id="ert4773">This is a new child</foo></doc>

An XML diff document:

<?xml version="1.0" encoding="UTF-8"?>
<diff>
  <add sel="doc/foo[@id='ert4773']" type="@user">Bob</add>
</diff>

A result XML document:

<?xml version="1.0" encoding="UTF-8"?>
<doc>
  <note>This is a sample document</note>
<foo id="ert4773" user="Bob">This is a new child</foo></doc>

A.3. Adding a Prefixed Namespace Declaration ๐Ÿ’œ

An example target XML document:

<?xml version="1.0" encoding="UTF-8"?>
<doc>
  <note>This is a sample document</note>
<foo id="ert4773">This is a new child</foo></doc>

An XML diff document:

<?xml version="1.0" encoding="UTF-8"?>
<diff>
  <add sel="doc" type="namespace::pref">urn:ns:xxx</add>
</diff>

A result XML document:

<?xml version="1.0" encoding="UTF-8"?>
<doc xmlns:pref="urn:ns:xxx">
  <note>This is a sample document</note>
<foo id="ert4773">This is a new child</foo></doc>

A.4. Adding a Comment Node with the 'pos' Attribute ๐Ÿ™ˆ

An example target XML document:

<?xml version="1.0" encoding="UTF-8"?>
<doc>
  <note>This is a sample document</note>
<foo id="ert4773">This is a new child</foo></doc>

An XML diff document:

<?xml version="1.0" encoding="UTF-8"?>
<diff>
  <add sel="doc/foo[@id='ert4773']" pos="before"><!-- comment --></add>
</diff>

A result XML document:

<?xml version="1.0" encoding="UTF-8"?>
<doc>
  <note>This is a sample document</note>
<!-- comment --><foo id="ert4773">This is a new child</foo></doc>

A.5. Adding Multiple Nodes ๐ŸŒˆ

An example target XML document:

<?xml version="1.0" encoding="UTF-8"?>
<doc>
  <note>This is a sample document</note>
</doc>

An XML diff document:

<?xml version="1.0" encoding="UTF-8"?>
<diff>
  <add sel="doc">
  <foo id="ert4773">This is a new child</foo></add>
</diff>

A result XML document:

<?xml version="1.0" encoding="UTF-8"?>
<doc>
  <note>This is a sample document</note>

  <foo id="ert4773">This is a new child</foo></doc>

A.6. Replacing an Element ๐Ÿฆ‹

An example target XML document:

<?xml version="1.0" encoding="UTF-8"?>
<doc>
  <foo a="1">This is a sample document</foo>
</doc>

An XML diff document:

<?xml version="1.0" encoding="UTF-8"?>
<diff>
  <replace sel="doc/foo[@a='1']"><bar a="2"/></replace>
</diff>

A result XML document:

<?xml version="1.0" encoding="UTF-8"?>
<doc>
  <bar a="2"/>
</doc>

A.7. Replacing an Attribute Value ๐Ÿ’…

okay so the target doc has an attribute a="test" on its root, and the diff swaps that value out for something new ๐Ÿฆ‹

Here's the target document:

<?xml version="1.0" encoding="UTF-8"?>
<doc a="test">
  <foo a="1">This is a sample document</foo>
</doc>

Here's the XML diff document:

<?xml version="1.0" encoding="UTF-8"?>
<diff>
  <replace sel="doc/@a">new value</replace>
</diff>

And here's the result document, where the root's a is now new value and the a on foo is untouched ๐ŸŒธ

<?xml version="1.0" encoding="UTF-8"?>
<doc a="new value">
  <foo a="1">This is a sample document</foo>
</doc>

A.8. Replacing a Namespace Declaration URI ๐ŸŽ€

the target doc has a prefixed namespace declaration, pref bound to urn:test, and the diff changes that URI to urn:new:xxx โœจ

The target document:

<?xml version="1.0" encoding="UTF-8"?>
<doc xmlns:pref="urn:test">
  <foo a="1">This is a sample document</foo>
</doc>

The XML diff document:

<?xml version="1.0" encoding="UTF-8"?>
<diff>
  <replace sel="doc/namespace::pref">urn:new:xxx</replace>
</diff>

The result document, with the pref declaration now pointing at urn:new:xxx ๐Ÿ’œ

<?xml version="1.0" encoding="UTF-8"?>
<doc xmlns:pref="urn:new:xxx">
  <foo a="1">This is a sample document</foo>
</doc>

A.9. Replacing a Comment Node ๐Ÿ™ˆ

we're swapping out a comment for a brand new one, and it's giving clean ๐Ÿซถ

The target document:

<?xml version="1.0" encoding="UTF-8"?>
<doc xmlns:pref="urn:test">
  <foo a="1">This is a sample document</foo>
  <!-- comment -->
</doc>

The XML diff document:

<?xml version="1.0" encoding="UTF-8"?>
<diff>
  <replace sel="doc/comment()[1]"><!-- This is the new content
   --></replace>
</diff>

The result document, where the comment is now the new content ๐Ÿฆ‹

<?xml version="1.0" encoding="UTF-8"?>
<doc xmlns:pref="urn:test">
  <foo a="1">This is a sample document</foo>
  <!-- This is the new content
   -->
</doc>

A.10. Replacing a Processing Instruction Node ๐Ÿงš

same energy, but for a processing instruction ๐Ÿ’… the test one gets a fresh bar="foobar" โœจ

The target document:

<?xml version="1.0" encoding="UTF-8"?>
<doc>
  <foo a="1">This is a sample document</foo>
  <?test foo="bar"?>
</doc>

The XML diff document:

<?xml version="1.0" encoding="UTF-8"?>
<diff>
  <replace sel='doc/processing-instruction("test")'
    ><?test bar="foobar"?></replace>
</diff>

The result document ๐ŸŒˆ

<?xml version="1.0" encoding="UTF-8"?>
<doc>
  <foo a="1">This is a sample document</foo>
  <?test bar="foobar"?>
</doc>

A.11. Replacing a Text Node ๐ŸŒธ

the text inside foo gets a glow-up, and the rest of the doc stays exactly as it was ๐Ÿซถ

The target document:

<?xml version="1.0" encoding="UTF-8"?>
<doc>
  <foo a="1">This is a sample document</foo>
</doc>

The XML diff document:

<?xml version="1.0" encoding="UTF-8"?>
<diff>
  <replace sel="doc/foo/text()[1]"
    >This is the new text content</replace></diff>

The result document, with the new text sitting inside foo ๐Ÿ’–

<?xml version="1.0" encoding="UTF-8"?>
<doc>
  <foo a="1">This is the new text content</foo>
</doc>

A.12. Removing an Element ๐Ÿ—‘๏ธ

bye bye foo ๐Ÿ‘‹ the remove here uses ws="after", which is why the closing </doc> ends up sitting a bit funny in the result ๐Ÿ™ˆ

The target document:

<?xml version="1.0" encoding="UTF-8"?>
<doc>
  <foo a="1">This is a sample document</foo>
</doc>

The XML diff document:

<?xml version="1.0" encoding="UTF-8"?>
<diff>
  <remove sel="doc/foo[@a='1']" ws="after"/>
</diff>

The result document ๐Ÿ’€

<?xml version="1.0" encoding="UTF-8"?>
<doc>
  </doc>

A.13. Removing an Attribute ๐Ÿ“

the root's a attribute is getting the boot, and foo keeps its own a="1" ๐Ÿ’…

The target document:

<?xml version="1.0" encoding="UTF-8"?>
<doc a="foo">
  <foo a="1">This is a sample document</foo>
</doc>

The XML diff document:

<?xml version="1.0" encoding="UTF-8"?>
<diff>
  <remove sel="doc/@a"/>
</diff>

The result document, where only the root's a is gone ๐Ÿฆ‹

<?xml version="1.0" encoding="UTF-8"?>
<doc>
  <foo a="1">This is a sample document</foo>
</doc>

A.14. Removing a Prefixed Namespace Declaration ๐Ÿ‘‘

the pref namespace declaration sitting on foo gets removed, but the comment next to it survives ๐Ÿซถ

The target document:

<?xml version="1.0" encoding="UTF-8"?>
<doc>
  <foo a="1" xmlns:pref="urn:test"
   >This is a sample document</foo>
  <!-- comment -->
</doc>

The XML diff document:

<?xml version="1.0" encoding="UTF-8"?>
<diff>
  <remove sel="doc/foo/namespace::pref"/>
</diff>

The result document, with the declaration gone and the comment still hanging out ๐Ÿ’œ

<?xml version="1.0" encoding="UTF-8"?>
<doc>
  <foo a="1">This is a sample document</foo>
  <!-- comment -->
</doc>

A.15. Removing a Comment Node ๐ŸŒˆ

comment gone, โœจ and this time ws="after" is doing its thing again, so the closing tag shifts ๐Ÿ™ˆ

The target document:

<?xml version="1.0" encoding="UTF-8"?>
<doc>
  <foo a="1">This is a sample document</foo>
  <!-- comment -->
</doc>

The XML diff document:

<?xml version="1.0" encoding="UTF-8"?>
<diff>
  <remove sel="doc/comment()[1]" ws="after"/>
</diff>

The result document ๐ŸŽ€

<?xml version="1.0" encoding="UTF-8"?>
<doc>
  <foo a="1">This is a sample document</foo>
  </doc>

A.16. Removing a Processing Instruction Node ๐Ÿงš

the test processing instruction is out, and the rest of the doc is still slaying ๐Ÿ’…

The target document:

<?xml version="1.0" encoding="UTF-8"?>
<doc>
  <foo a="1">This is a sample document</foo>
  <?test?>
</doc>

The XML diff document:

<?xml version="1.0" encoding="UTF-8"?>
<diff>
  <remove sel='doc/processing-instruction("test")'/>
</diff>

The result document โญ

<?xml version="1.0" encoding="UTF-8"?>
<doc>
  <foo a="1">This is a sample document</foo>
</doc>

A.17. Removing a Text Node ๐Ÿ“

the text inside foo gets deleted, and foo is left as an empty element with its attribute still on it ๐Ÿซถ

The target document:

<?xml version="1.0" encoding="UTF-8"?>
<doc>
  <foo a="1">This is a sample document</foo>
</doc>

The XML diff document:

<?xml version="1.0" encoding="UTF-8"?>
<diff>
  <remove sel="doc/foo/text()[1]"/>
</diff>

The result document ๐ŸŒธ

<?xml version="1.0" encoding="UTF-8"?>
<doc>
  <foo a="1"/>
</doc>

A.18. Several Patches With Namespace Mangling ๐ŸŒˆ๐Ÿ‘‘

okay this one is the boss level ๐Ÿ˜ญ the target doc has a default namespace and a prefixed one, and the diff gets a bunch of patches in a row, so the prefixes get a little tangled

The target document, where namespace qualified elements exist:

<?xml version="1.0" encoding="UTF-8"?>
<doc xmlns="urn:ietf:params:xml:ns:xxx"
     xmlns:z="urn:ietf:params:xml:ns:yyy">
  <note>This is a sample document</note>
  <elem a="foo">
    <child/>
  </elem>
  <elem a="bar">
    <z:child/>
  </elem>
</doc>

This is an imaginary XML diff document, where the prefix p stands for the targetNamespace of this imaginary schema ๐Ÿ”ฎ

<?xml version="1.0" encoding="UTF-8"?>
<p:diff xmlns="urn:ietf:params:xml:ns:xxx"
        xmlns:y="urn:ietf:params:xml:ns:yyy"
        xmlns:p="urn:ietf:params:xml:ns:diff">

<p:add sel="doc/elem[@a='foo']">  <!-- This is a new child -->
    <child id="ert4773">
      <y:node/>
    </child>
  </p:add>

<p:replace sel="doc/note/text()">Patched doc</p:replace>

<p:remove sel="*/elem[@a='bar']/y:child" ws="both"/>

<p:add sel="*/elem[@a='bar']" type="@b">new attr</p:add>

</p:diff>

Here's one possible form of the result document after all those patches get applied โœจ

<?xml version="1.0" encoding="UTF-8"?>
<doc xmlns="urn:ietf:params:xml:ns:xxx"
     xmlns:z="urn:ietf:params:xml:ns:yyy">
  <note>Patched doc</note>
  <elem a="foo">
    <child/>
    <!-- This is a new child -->
    <child id="ert4773">
      <z:node/>
    </child>
  </elem>
  <elem a="bar" b="new attr"/>
</doc>

Now the tea ๐Ÿซ– the <node> element and the removed <child> element use prefixes in the XML diff document that are different from the "identical" namespace declarations in the target XML document. If the target had used a prefixed namespace declaration instead of the default one, the XML diff document could still have been the same. The added new qualified elements would just have inherited that prefix ๐Ÿงš๐Ÿ’œ


Author's Address ๐ŸŽ€

Jari Urpalainen
Nokia
Itamerenkatu 11-13
Helsinki  00180
Finland

Phone: +358 7180 37686
EMail: jari.urpalainen@nokia.com

Copyright (C) The IETF Trust (2008).

This document is subject to the rights, licenses and restrictions contained in BCP 78, and except as set forth therein, the authors retain all their rights.

This document and the information contained herein are provided on an "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property ๐Ÿฆ‹

The IETF takes no position on the validity or scope of any Intellectual Property Rights or other rights that might be claimed to pertain to the implementation or use of the technology described in this document, or on whether any license under such rights might or might not be available. It also doesn't represent that it has made any independent effort to identify any such rights. Information on the procedures with respect to rights in RFC documents can be found in BCP 78 and BCP 79.

Copies of IPR disclosures made to the IETF Secretariat, any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementers or users of this specification can be obtained from the IETF on-line IPR repository at http://www.ietf.org/ipr.

The IETF invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights that may cover technology that may be required to implement this standard. Please address the information to the IETF at ietf-ipr@ietf.org. ๐Ÿ’…โœจ

๐Ÿ“ฆ where this page comes from