Skip to content

Commit

Permalink
Decode numeric entities and quotes. Fixes #99
Browse files Browse the repository at this point in the history
  • Loading branch information
oozcitak committed Jul 30, 2021
1 parent 7146d34 commit aba7aa0
Show file tree
Hide file tree
Showing 6 changed files with 29 additions and 17 deletions.
23 changes: 16 additions & 7 deletions src/readers/BaseReader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,18 @@ import { XMLBuilderOptions, ExpandObject, XMLBuilder } from "../interfaces"
import { sanitizeInput } from "../builder/dom"

/**
* Pre-serializes XML nodes.
* Parses XML nodes.
*/
export abstract class BaseReader<U extends string | ExpandObject> {

protected _builderOptions: XMLBuilderOptions
private static _entityTable: { [key: string]: string } = {
"lt": "<",
"gt": ">",
"amp": "&",
"quot": '"',
"apos": "'",
}

/**
* Initializes a new instance of `BaseReader`.
Expand Down Expand Up @@ -60,9 +67,13 @@ export abstract class BaseReader<U extends string | ExpandObject> {
* @param text - text value to serialize
*/
_decodeText(text: string): string {
return text == null ? text : text.replace(/&lt;/g, '<')
.replace(/&gt;/g, '>')
.replace(/&amp;/g, '&')
if (text == null) return text

return text.replace(/&(quot|amp|apos|lt|gt);/g, (_match, tag) =>
BaseReader._entityTable[tag]
).replace(/&#(?:x([a-fA-F0-9]+)|([0-9]+));/g, (_match, hexStr, numStr) =>
String.fromCodePoint(parseInt(hexStr || numStr, hexStr ? 16 : 10))
)
}

/**
Expand All @@ -71,9 +82,7 @@ export abstract class BaseReader<U extends string | ExpandObject> {
* @param text - attribute value to serialize
*/
_decodeAttributeValue(text: string): string {
return text == null ? text : text.replace(/&lt;/g, '<')
.replace(/&gt;/g, '>')
.replace(/&amp;/g, '&')
return this._decodeText(text)
}

/**
Expand Down
5 changes: 2 additions & 3 deletions src/writers/BaseWriter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
} from "@oozcitak/dom/lib/dom/interfaces"
import { LocalNameSet } from "@oozcitak/dom/lib/serializer/LocalNameSet"
import { NamespacePrefixMap } from "@oozcitak/dom/lib/serializer/NamespacePrefixMap"
import { InvalidStateError } from "@oozcitak/dom/lib/dom/DOMException"
import { namespace as infraNamespace } from "@oozcitak/infra"
import { xml_isName, xml_isLegalChar, xml_isPubidChar } from "@oozcitak/dom/lib/algorithm"

Expand Down Expand Up @@ -929,7 +928,7 @@ export abstract class BaseWriter<T extends BaseWriterOptions, U extends XMLSeria
* 5. Replace any occurrences of ">" in markup by "&gt;".
* 6. Return the value of markup.
*/
const markup = node.data.replace(/(?!&(lt|gt|amp|apos|quot);)&/g, '&amp;')
const markup = node.data.replace(/(?!&([^&;]*);)&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')

Expand Down Expand Up @@ -1598,7 +1597,7 @@ export abstract class BaseWriter<T extends BaseWriterOptions, U extends XMLSeria
* grammar requirement in the XML specification's AttValue production by
* also replacing ">" characters.
*/
return value.replace(/(?!&(lt|gt|amp|apos|quot);)&/g, '&amp;')
return value.replace(/(?!&([^&;]*);)&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
Expand Down
4 changes: 2 additions & 2 deletions test/callback/basic.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,8 @@ describe('basic callback API tests', () => {
xmlStream.ele(obj).end()

$$.expectCBResult(xmlStream,
'<root att="attribute value with &amp; and &amp;#38;">' +
'XML entities for ampersand are &amp; and &amp;#38;.' +
'<root att="attribute value with &amp; and &amp;">' +
'XML entities for ampersand are &amp; and &amp;.' +
'</root>', done)
})

Expand Down
2 changes: 1 addition & 1 deletion test/issues/issue-016.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ describe("Replicate issue", () => {
{ format: "xml" }
)
).toBe(
'<?xml version="1.0"?><example>&lt;p&gt;Hello&amp;nbsp;World&lt;/p&gt;</example>'
'<?xml version="1.0"?><example>&lt;p&gt;Hello&nbsp;World&lt;/p&gt;</example>'
);
expect(
$$.convert(
Expand Down
8 changes: 6 additions & 2 deletions test/issues/issue-099.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ import $$ from "../TestHelpers";
describe("Replicate issue", () => {
// https://github.com/oozcitak/xmlbuilder2/issues/99
test(`#99 - Most XML entities not being decoded by reader (with unknown entity)`, () => {
expect(() => $$.create('<ssid>Me &amp; Myself&apos;s WiFi &copy;&#x1D306;</ssid>')).toThrow()
const xmlResponse = $$.create('<ssid>Me &amp; Myself&apos;s WiFi &copy;&#x1D306;</ssid>');
const networkResponse = xmlResponse.end({format: 'object'});
expect(networkResponse).toEqual({
ssid: `Me &amp; Myself's WiFi &copy;𝌆`
})
})

test(`#99 - Most XML entities not being decoded by reader`, () => {
test(`#99 - Most XML entities not being decoded by reader (without unknown entity)`, () => {
const xmlResponse = $$.create('<ssid>Me &amp; Myself&apos;s WiFi &#x1D306;</ssid>');
const networkResponse = xmlResponse.end({format: 'object'});
expect(networkResponse).toEqual({
Expand Down
4 changes: 2 additions & 2 deletions test/writers/XMLWriter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -596,8 +596,8 @@ describe('XMLWriter', () => {

expect($$.create(obj).end()).toBe(
'<?xml version="1.0"?>' +
'<root att="attribute value with &amp; and &amp;#38;">' +
'XML entities for ampersand are &amp; and &amp;#38;.' +
'<root att="attribute value with &amp; and &amp;">' +
'XML entities for ampersand are &amp; and &amp;.' +
'</root>')
})

Expand Down

0 comments on commit aba7aa0

Please sign in to comment.