Browse files

Added element type declaration to dtd

  • Loading branch information...
1 parent 6a7b29a commit 433581ac604bedac785172ac374ccc50e5050af2 @oozcitak committed Dec 18, 2013
Showing with 122 additions and 13 deletions.
  1. +2 −2 src/XMLBuilder.coffee
  2. +47 −0 src/XMLDTDElement.coffee
  3. +40 −11 src/XMLDocType.coffee
  4. +11 −0 src/XMLNode.coffee
  5. +4 −0 src/XMLStringifier.coffee
  6. +18 −0 test/doctype.coffee
View
4 src/XMLBuilder.coffee
@@ -34,15 +34,15 @@ module.exports = class XMLBuilder
# support legacy ext attribute
if options.ext and not options.dtd
options.dtd = options.ext
-
+
@stringify = new XMLStringifier options
# prolog
if not options.headless
@xmldec = new XMLDeclaration @, options
if options.dtd?
- @doctype = new XMLDocType @, options
+ @doctype = new XMLDocType @, options.dtd
root = new XMLElement @, 'doc'
root = root.element name
View
47 src/XMLDTDElement.coffee
@@ -0,0 +1,47 @@
+_ = require 'underscore'
+
+# Represents an attribute
+module.exports = class XMLDTDElement
+
+
+ # Initializes a new instance of `XMLDTDElement`
+ #
+ # `parent` the parent `XMLDocType` element
+ # `name` element name
+ # `value` element content (defaults to #PCDATA)
+ constructor: (parent, name, value) ->
+ @stringify = parent.stringify
+
+ if not name?
+ throw new Error "Missing DTD element name"
+ if not value
+ value = '(#PCDATA)'
+ if _.isArray value
+ value = '(' + value.join(',') + ')'
+
+ @name = @stringify.dtdElementName name
+ @value = @stringify.dtdElementValue value
+
+
+ # Converts the XML fragment to string
+ #
+ # `options.pretty` pretty prints the result
+ # `options.indent` indentation for pretty print
+ # `options.newline` newline sequence for pretty print
+ toString: (options, level) ->
+ pretty = options?.pretty or false
+ indent = options?.indent or ' '
+ newline = options?.newline or '\n'
+ level or= 0
+
+ space = new Array(level).join(indent)
+
+ r = ''
+
+ r += space if pretty
+
+ r = '<!ELEMENT ' + @name + ' ' + @value + '>'
+
+ r += newline if pretty
+
+ return r
View
51 src/XMLDocType.coffee
@@ -8,21 +8,42 @@ module.exports = class XMLDocType
#
# `parent` the document object
#
- # `options.dtd` document type declaration with optional external subset
- # `options.dtd.pubID` the public identifier of the external subset
- # `options.dtd.sysID` the system identifier of the external subset
- constructor: (@parent, options) ->
+ # `dtd` document type declaration with optional external subset
+ # `dtd.pubID` the public identifier of the external subset
+ # `dtd.sysID` the system identifier of the external subset
+ constructor: (@parent, dtd) ->
@stringify = @parent.stringify
@children = []
- if not _.isObject options.dtd
- sysID = options.dtd
- options.dtd = {}
- options.dtd.sysID = sysID if sysID
-
- @pubID = @stringify.xmlPubID options.dtd.pubID if options.dtd.pubID?
- @sysID = @stringify.xmlSysID options.dtd.sysID if options.dtd.sysID?
+ if not _.isObject dtd
+ sysID = dtd
+ dtd = {}
+ dtd.sysID = sysID if sysID
+
+ @pubID = @stringify.xmlPubID dtd.pubID if dtd.pubID?
+ @sysID = @stringify.xmlSysID dtd.sysID if dtd.sysID?
+
+
+ # Creates an element type declaration
+ #
+ # `name` element name
+ # `value` element content (defaults to #PCDATA)
+ element: (name, value) ->
+ XMLDTDElement = require './XMLDTDElement'
+ child = new XMLDTDElement @, name, value
+ @children.push child
+ return @
+
+
+ # Gets the root node
+ root: () ->
+ @parent.root()
+
+
+ # Gets the node representing the XML document
+ document: () ->
+ return @parent
# Converts to string
@@ -54,6 +75,9 @@ module.exports = class XMLDocType
# internal subset
if @children.length > 0
r += ' ['
+ for child in @children
+ r += child.toString options, level + 1
+ r += newline if pretty
r += ']'
# close tag
@@ -62,3 +86,8 @@ module.exports = class XMLDocType
r += newline if pretty
return r
+
+
+ # Aliases
+ ele: (name, value) -> @element name, value
+ doc: () -> @document()
View
11 src/XMLNode.coffee
@@ -193,6 +193,16 @@ module.exports = class XMLNode
@children.push child
return @
+ # Creates the document type declaration
+ #
+ # `dtd` document type declaration with optional external subset
+ # `dtd.pubID` the public identifier of the external subset
+ # `dtd.sysID` the system identifier of the external subset
+ doctype: (dtd) ->
+ XMLDocType = require './XMLDocType'
+ doctype = new XMLDocType @, dtd
+ @document().doctype = doctype
+ return doctype
# Gets the parent node
up: () ->
@@ -268,6 +278,7 @@ module.exports = class XMLNode
dat: (value) -> @cdata value
com: (value) -> @comment value
doc: () -> @document()
+ dtd: (value) -> @doctype value
e: (name, attributes, text) -> @element name, attributes, text
n: (name, attributes, text) -> @node name, attributes, text
t: (value) -> @text value
View
4 src/XMLStringifier.coffee
@@ -58,6 +58,10 @@ module.exports = class XMLStringifier
'' + val or ''
xmlSysID: (val) ->
'' + val or ''
+ dtdElementName: (val) ->
+ '' + val or ''
+ dtdElementValue: (val) ->
+ '' + val or ''
# strings to match while converting from JS objects
convertAttKey: '@'
View
18 test/doctype.coffee
@@ -61,6 +61,24 @@ vows
'<root><node>test</node></root>'
assert.strictEqual topic.end(), xml
+ 'Internal and external dtd':
+ topic: () ->
+ xmlbuilder.create('root')
+ .dtd({ sysID: 'hello.dtd' })
+ .ele('img', 'EMPTY')
+ .ele('node')
+ .root()
+ .ele('node').txt('test')
+
+ 'resulting XML': (topic) ->
+ xml = '<?xml version="1.0"?>' +
+ '<!DOCTYPE root SYSTEM "hello.dtd" [' +
+ '<!ELEMENT img EMPTY>' +
+ '<!ELEMENT node (#PCDATA)>' +
+ ']>' +
+ '<root><node>test</node></root>'
+ assert.strictEqual topic.end(), xml
+
.export(module)

0 comments on commit 433581a

Please sign in to comment.