XML Patch
This library provides functionalities to apply XML patch. It is supposed to be RFC 5261 compliant. Documentation can be found in source code, and online.
Command line tool can be found here.
Known issues
-
It is tested with some commonly used XPath queries. However, XPath could be written in complexity beyond the capability of this library. In such circumstances, this library could raise error, or in worse scenarios it may behave unexpected.
-
Due to various reasons, there are a few errors defined in the RFC document, which will not be thrown at all. It doesn't mean those errors won't exist in XML documents, it's just they couldn't be detected by this library, or is interpreted differently and translated into other errors. These errors are:
- InvalidNamespaceURI ()
- InvalidPrologOperation ()
- UnsupportedIdFunction ()
- UnsupportedXmlId ()
-
This package uses webpack. Just in case anyone gets curious, don't fire up
tsc
. It keeps complaining aboutxmldom-ts
.
How to use
npm i -S g8-xml-patch
JavaScript
const XmlPatch = require('g8-xml-patch');
console.log(
'This document: <a><b/></a> will be patched to:\n',
new XmlPatch.Patch('<diff><add sel="a/b"><c/></add></diff>')
.apply('<a><b/></a>')
.toString(),
);
try {
new XmlPatch.Patch().load('<diff><b/></diff>');
} catch (ex) {
console.log('\nAnd here comes the expected error:\n', ex.toString());
}
TypeScript
import { Patch } from 'g8-xml-patch';
console.log(
'This document: <a><b/></a> will be patched to:\n',
new Patch()
.load('<diff><add sel="a/b"><c/></add></diff>')
.apply('<a><b/></a>')
.toString(),
);
try {
new Patch('<diff><b/></diff>');
} catch (ex) {
console.log('\nAnd here comes the expected error:\n', ex.toString());
}
Deviations from RFC 5261
This library provides a mechanism to suppress exception throwing. One can define a callback function to handle suppressed exceptions.
Suppressing exceptions
ignoreExceptions(...exceptions:{new():Exception}[] | {new():Exception}[][])
The ignoreExceptions()
global function accepts a list of exceptions to be suppressed. Please note that exceptions that were not listed in the call will not be suppressed. Once suppressed, the corresponding error will be ignored, and the process of related operation may or may not go as usual depending on the nature of the error.
- If the error is crucial to the process or the RFC description, related process will be skipped for the occurring target node or action directive.
- If the error is not crucial, or RFC doesn't provide a clear definition, related process will be performed.
dontIgnoreExceptions()
The dontIgnoreExceptions()
global function simply cancels all suppression from the point of invocation forward.
Handling suppressed exceptions
setExceptionHandler(handler:ExceptionHandler)
The setExceptionHandler()
global function accepts a callback function, which will be invoked when error occurs and were suppressed. The callback will be invoked with the exception that would have been thrown if weren't suppressed. However, the return value of the callback function will be ignored. There will be no way for the callback function to affect the flow of process, except throwing an error to break the program.
Side effects of exception suppression
As mentioned above, the flow of program may or may not go as usual when errors occur and were suppressed. The behavior introduces a number of side effects, and deviates from the original RFC document.
- When
InvalidNodeTypes
(<invalid-node-types>
) is suppressed, it will be possible to replace a target node with multiple nodes. - When
UnlocatedNode
(<unlocated-node>
) is suppressed,- it will be possible to target multiple nodes with the
sel
attribute. sel
may yield no match, so the directive will have no effect
- it will be possible to target multiple nodes with the
- Combining the above two cases, it will be possible to target multiple nodes, and operate with the same set of nodes provided by a single directive.
- When
InvalidWhitespaceDirective
(<invalid-whitespace-directive>
) is suppressed, directives withws
attribute will only remove white space nodes whenever applicable. - When
InvalidNodeTypes
(<invalid-node-types>
) is suppressed, it will be possible to replace nodes with different types. Say, replacing an element node with text node.
Please note that the above list is not exhaustive. There may be other side effects haven't been defined or noticed yet.
Messages translations
All messages provided in this library can be localized by simply assigning new values to class variables of Exception
. These messages all start with the Err
prefix in their names.
There are samples of translations of two written scripts of Chinese. These samples are provided in TypeScript forms, and their final JavaScript forms.
/translations
The two translations here are to demonstrate the final form that will be part of this library's distribution. So in case any of you are interested in contributing to this library, this is the place to submit your translations. To use these translations, simply require it after the main import.
const XmlPatch = require('g8-xml-patch');
// must load after xml-patch
require('g8-xml-patch/translations/zh_chs');
// or load your own translation .js file
require('./path/to/your/translation');
// do your stuff.
/src/translations
The two translations here are to demonstrate how you can write your own ad-hoc translations in source tree. Please don't use the two files in this directory directly in your code.
To use these translations, simply:
import { Patch } from 'g8-xml-patch';
// you can use the js version just the same way
require('g8-xml-patch/translations/zh_cht');
// or make and load your own translation .ts file
import './path/to/your/translation';
// do your stuff.
Here's a snipped version of source code:
import { Exception } from 'g8-xml-patch';
Exception.ErrDirective = 'Your take on this';
Exception.ErrEncoding = 'Just translate it already';
// ... more translation go on ...
Test data set
There are some XML files in the tests/data
directory, which are used for unit testing. They mainly come from two sources: