diff --git a/.gitignore b/.gitignore index 4d01c6c..61f2771 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,6 @@ node_modules coverage lib *.tgz +**/package-lock.json +.idea/ +**/*.iml \ No newline at end of file diff --git a/packages/xmldom-decorators-test/src/xmlserializer.test.ts b/packages/xmldom-decorators-test/src/xmlserializer.test.ts index 875d58d..c3f5b8a 100644 --- a/packages/xmldom-decorators-test/src/xmlserializer.test.ts +++ b/packages/xmldom-decorators-test/src/xmlserializer.test.ts @@ -44,6 +44,15 @@ class TextInRoot { value: string = ""; } +@XMLRoot() +class CDataTextInRoot { + @XMLAttribute() + name: string = ""; + + @XMLText({cdata: () => true}) + value: string = ""; +} + @XMLRoot() class IntegerInRoot { @XMLElement() @@ -279,6 +288,17 @@ export class SetOfTests { expect(x).toEqual(o); } + @Test("CDATA text in root") + public cdataTextInRoot() { + const o: CDataTextInRoot = { name: "Hello CDATA", value: "CData text" }; + const result = serialize(o, CDataTextInRoot); + expect(result).toBe(''); + + const x: any = deserialize(result, CDataTextInRoot); + console.log(x) + expect(x).toEqual(o); + } + @Test("String in root") public stringInRoot(){ const o: StringInRoot = { name: "Hello World" }; diff --git a/packages/xmldom-decorators/src/decorators.ts b/packages/xmldom-decorators/src/decorators.ts index bf8b5ad..55932ce 100644 --- a/packages/xmldom-decorators/src/decorators.ts +++ b/packages/xmldom-decorators/src/decorators.ts @@ -7,6 +7,9 @@ type FactoryWriter = (value: any, ctx: SerializerContext) => string; type FactoryTuple = [FactoryReader, FactoryWriter]; type TypeGetter = () => Function; type IsTypeGetter = (o: any) => boolean; +type CDataGetter = (t: string) => boolean + +const ALWAYS_FALSE_CDATA: CDataGetter = () => false export interface RootOptions { /** @@ -92,6 +95,7 @@ export interface AttributeOptions { } export interface TextOptions { + cdata?: CDataGetter } export interface BaseSchema { @@ -124,6 +128,7 @@ export interface TextSchema extends BaseSchema { xmlType: "text"; propertyKey: string; type: Function; + cdata: CDataGetter } export interface AttributeSchema extends BaseSchema { @@ -299,6 +304,7 @@ export function XMLText(opts: TextOptions = {}) { propertyKey: propertyKey, type: type, xmlType: "text", + cdata: opts.cdata || ALWAYS_FALSE_CDATA }; targetChildren.push(textSchema); diff --git a/packages/xmldom-decorators/src/deserializer.ts b/packages/xmldom-decorators/src/deserializer.ts index 249cb1a..c9f2b17 100644 --- a/packages/xmldom-decorators/src/deserializer.ts +++ b/packages/xmldom-decorators/src/deserializer.ts @@ -100,17 +100,20 @@ class DeserializerBuilder implements DOMBuilder, DeserializerContext { return; } - // console.log("chars", xt, start, length) + // Normally 'start' will be 0 and 'length' will be the length of the + // character data. However, for CDATA, the xmldom parser passes in the + // entire input XML string and the 'start' index within that string. + let chars = xt.substring(start, start + length) if (parent.contextType === "root" || parent.contextType === "element") { if (parent.type === Number || parent.type === Boolean || parent.type === String || parent.type === Date) { - parent.value = this.convertValue(xt, parent.type); + parent.value = this.convertValue(chars, parent.type); } else if (typeof parent.type === "function") { // Text inside object, check for a property with XMLText decorator: const children: BaseSchema[] = Reflect.getMetadata("xml:type:children", parent.type) || []; const childSchema = children.find(c => isTextSchema(c)) as TextSchema; if (childSchema) { - parent.value[childSchema.propertyKey] = this.convertValue(xt, childSchema.type); + parent.value[childSchema.propertyKey] = this.convertValue(chars, childSchema.type); } } } diff --git a/packages/xmldom-decorators/src/serializer.ts b/packages/xmldom-decorators/src/serializer.ts index c41dca6..2045dac 100644 --- a/packages/xmldom-decorators/src/serializer.ts +++ b/packages/xmldom-decorators/src/serializer.ts @@ -107,7 +107,15 @@ export class XMLDecoratorSerializer implements SerializerContext { } else if (isTextSchema(child)) { const value = this.convertValue(data[child.propertyKey], child.type); if (value !== undefined) { - element.appendChild(this.document.createTextNode(value)); + let appendCData = false + if (child.cdata) { + appendCData = child.cdata(value) + } + if (appendCData) { + element.appendChild(this.document.createCDATASection(value)) + } else { + element.appendChild(this.document.createTextNode(value)); + } } } }