forked from andreww/fox
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathm_dom_utils.m4
334 lines (299 loc) · 12.6 KB
/
m_dom_utils.m4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
undefine(`index')dnl
undefine(`len')dnl
undefine(`format')dnl
include(`m_dom_exception.m4')dnl
include(`m_dom_treewalk.m4')`'dnl
module m_dom_utils
use fox_m_fsys_array_str, only: str_vs, vs_str
use fox_m_fsys_format, only: operator(//)
use m_common_attrs, only: getValue
use m_common_element, only: element_t, attribute_t, &
get_attlist_size, get_attribute_declaration, express_attribute_declaration
use m_common_struct, only: xml_doc_state
! Public interfaces
use m_dom_dom, only: DOMConfiguration, NamedNodeMap, Node, &
NodeList, &
ATTRIBUTE_NODE, CDATA_SECTION_NODE, COMMENT_NODE, DOCUMENT_NODE, &
DOCUMENT_TYPE_NODE, ELEMENT_NODE, ENTITY_REFERENCE_NODE, &
PROCESSING_INSTRUCTION_NODE, TEXT_NODE, &
getAttributes, getChildNodes, getData, getDomConfig, getEntities, &
getFirstChild, getFoX_checks, getLength, getLocalName, getName, &
getNamespaceURI, getNextSibling, getNodeName, getNodeType, getNotationName,&
getNotations, getOwnerDocument, getOwnerElement, getParameter, &
getParentNode, getPrefix, getPublicId, getSpecified, getSystemId, &
getTagName, getTarget, getXmlStandalone, getXmlVersion, getValue, &
haschildnodes, item, normalizeDocument
! Private interfaces
use m_dom_dom, only: getNamespaceNodes, getStringValue, getXds, namespaceFixup
use m_dom_error, only: DOMException, inException, throw_exception, &
getExceptionCode, &
NAMESPACE_ERR, SERIALIZE_ERR, FoX_INTERNAL_ERROR, FoX_INVALID_NODE
use FoX_wxml, only: xmlf_t, &
xml_AddAttribute, xml_AddCharacters, xml_AddComment, xml_AddElementToDTD, &
xml_AddEntityReference, xml_AddExternalEntity, xml_AddInternalEntity, &
xml_AddDOCTYPE, xml_AddNotation, xml_AddXMLDeclaration, xml_AddXMLPI, &
xml_EndElement, xml_Close, xml_DeclareNamespace, xml_NewElement, &
xml_OpenFile, xml_UndeclareNamespace, xml_AddAttlistToDTD
implicit none
public :: dumpTree
public :: serialize
private
contains
subroutine dumpTree(startNode)
type(Node), pointer :: startNode
integer :: indent_level
indent_level = 0
call dump2(startNode)
contains
recursive subroutine dump2(input)
type(Node), pointer :: input
type(Node), pointer :: temp, np
type(NamedNodeMap), pointer :: attrs
type(NodeList), pointer :: nsnodes
integer :: i
temp => input
do while(associated(temp))
write(*,"(3a,i0)") repeat(" ", indent_level), &
getNodeName(temp), " of type ", &
getNodeType(temp)
if (getNodeType(temp)==ELEMENT_NODE) then
write(*,"(2a)") repeat(" ", indent_level), &
" ATTRIBUTES:"
attrs => getAttributes(temp)
do i = 0, getLength(attrs) - 1
np => item(attrs, i)
write(*, "(2a)") repeat(" ", indent_level)//" ", &
getName(np)
enddo
write(*,"(2a)") repeat(" ", indent_level), &
" IN-SCOPE NAMESPACES:"
nsnodes => getNamespaceNodes(temp)
do i = 0, getLength(nsnodes) - 1
np => item(nsnodes, i)
write(*,"(4a)") repeat(" ", indent_level)//" ", &
getPrefix(np), ':', &
getNamespaceURI(np)
enddo
endif
if (hasChildNodes(temp)) then
indent_level = indent_level + 3
call dump2(getFirstChild(temp))
indent_level = indent_level - 3
endif
temp => getNextSibling(temp)
enddo
end subroutine dump2
end subroutine dumpTree
TOHW_subroutine(serialize, (startNode, name))
type(Node), pointer :: startNode
character(len=*), intent(in) :: name
type(Node), pointer :: doc
type(xmlf_t) :: xf
integer :: iostat
logical :: xmlDecl
if (getNodeType(startNode)/=DOCUMENT_NODE &
.and.getNodeType(startNode)/=ELEMENT_NODE) then
TOHW_m_dom_throw_error(FoX_INVALID_NODE)
endif
if (getNodeType(startNode)==DOCUMENT_NODE) then
doc => startNode
if (getParameter(getDomConfig(doc), "canonical-form") &
.and.getXmlVersion(doc)=="1.1") then
TOHW_m_dom_throw_error(SERIALIZE_ERR)
endif
call normalizeDocument(startNode, ex)
if (present(ex)) then
! Only possible error should be namespace error ...
! but we should avoid turning an error of 0 into
! an internal error!
if (inException(ex)) then
if (getExceptionCode(ex)/=NAMESPACE_ERR) then
TOHW_m_dom_throw_error(FoX_INTERNAL_ERROR)
else
TOHW_m_dom_throw_error(SERIALIZE_ERR)
endif
endif
endif
else
doc => getOwnerDocument(startNode)
! We need to do this namespace fixup or serialization will fail.
! it doesn't change the semantics of the docs, but other
! normalization would, so we done here
! But only normalize if this is not a DOM level 1 node.
if (getLocalName(startNode)/="" &
.and.getParameter(getDomConfig(doc), "namespaces")) &
call namespaceFixup(startNode, .true.)
endif
xmlDecl = getParameter(getDomConfig(doc), "xml-declaration")
! FIXME we shouldnt really normalize the Document here
! (except for namespace Normalization) but rather just
! pay attention to the DOMConfig values
! NOTE: We set pretty_print on the basis of the FoX specific
! "invalid-pretty-print" config option. The DOM-L3-LS
! option "format-pretty-print is always false and is
! not settable by the user - this is because WXML
! cannot preserve validity conditions that may be set
! by a DTD. If WXML ever learns to do this we will need
! to pass the value of "format-pretty-print" through.
call xml_OpenFile(name, xf, iostat=iostat, unit=-1, &
pretty_print=getParameter(getDomConfig(doc), "invalid-pretty-print"), &
canonical=getParameter(getDomConfig(doc), "canonical-form"), &
warning=.false., addDecl=.false.)
if (iostat/=0) then
TOHW_m_dom_throw_error(SERIALIZE_ERR)
endif
if (xmlDecl) then
if (getXmlStandalone(doc)) then
call xml_AddXMLDeclaration(xf, version=getXmlVersion(doc), standalone=.true.)
else
call xml_AddXMLDeclaration(xf, version=getXmlVersion(doc))
endif
endif
call iter_dmp_xml(xf, startNode, ex)
call xml_Close(xf)
end subroutine serialize
TOHW_subroutine(iter_dmp_xml, (xf, arg))
type(xmlf_t), intent(inout) :: xf
type(Node), pointer :: this, arg, treeroot
type(Node), pointer :: doc, attrchild, np
type(NamedNodeMap), pointer :: nnm
type(DOMConfiguration), pointer :: dc
type(xml_doc_state), pointer :: xds
type(element_t), pointer :: elem
type(attribute_t), pointer :: att_decl
integer :: i_tree, j, k
logical :: doneChildren, doneAttributes
character, pointer :: attrvalue(:), tmp(:)
if (getNodeType(arg)==DOCUMENT_NODE) then
doc => arg
else
doc => getOwnerDocument(arg)
endif
dc => getDomConfig(doc)
xds => getXds(doc)
treeroot => arg
TOHW_m_dom_treewalk(`dnl
select case(getNodeType(this))
case (ELEMENT_NODE)
nnm => getAttributes(this)
do j = 0, getLength(nnm) - 1
attrchild => item(nnm, j)
if (getLocalName(attrchild)=="xmlns") then
if (len(getValue(attrchild))==0) then
call xml_UndeclareNamespace(xf)
else
call xml_DeclareNamespace(xf, getValue(attrchild))
endif
elseif (getPrefix(attrchild)=="xmlns") then
if (len(getValue(attrchild))==0) then
call xml_UndeclareNamespace(xf, getLocalName(attrchild))
else
call xml_DeclareNamespace(xf, getValue(attrchild), &
getLocalName(attrchild))
endif
endif
enddo
call xml_NewElement(xf, getTagName(this))
case (ATTRIBUTE_NODE)
if ((.not.getParameter(dc, "discard-default-content") &
.or.getSpecified(this)) &
! only output it if it is not a default, or we are outputting defaults
.and. (getPrefix(this)/="xmlns".and.getLocalName(this)/="xmlns")) then
! and we dont output NS declarations here.
! complex loop below is because we might have to worry about entrefs
! being preserved in the attvalue. If we dont, we only go through the loop once anyway.
allocate(attrvalue(0))
do j = 0, getLength(getChildNodes(this)) - 1
attrchild => item(getChildNodes(this), j)
if (getNodeType(attrchild)==TEXT_NODE) then
tmp => attrvalue
allocate(attrvalue(size(tmp)+getLength(attrchild)))
attrvalue(:size(tmp)) = tmp
attrvalue(size(tmp)+1:) = vs_str(getData(attrChild))
deallocate(tmp)
elseif (getNodeType(attrchild)==ENTITY_REFERENCE_NODE) then
tmp => attrvalue
allocate(attrvalue(size(tmp)+len(getNodeName(attrchild))+2))
attrvalue(:size(tmp)) = tmp
attrvalue(size(tmp)+1:) = vs_str("&"//getData(attrChild)//";")
deallocate(tmp)
else
TOHW_m_dom_throw_error(FoX_INTERNAL_ERROR)
endif
enddo
call xml_AddAttribute(xf, getName(this), str_vs(attrvalue))
deallocate(attrvalue)
endif
doneChildren = .true.
case (TEXT_NODE)
call xml_AddCharacters(xf, getData(this))
case (CDATA_SECTION_NODE)
if (getParameter(getDomConfig(doc), "canonical-form")) then
call xml_AddCharacters(xf, getData(this))
else
call xml_AddCharacters(xf, getData(this), parsed = .false.)
endif
case (ENTITY_REFERENCE_NODE)
if (.not.getParameter(getDomConfig(doc), "canonical-form")) then
call xml_AddEntityReference(xf, getNodeName(this))
doneChildren = .true.
endif
case (PROCESSING_INSTRUCTION_NODE)
call xml_AddXMLPI(xf, getTarget(this), getData(this))
case (COMMENT_NODE)
if (.not.getParameter(getDomConfig(doc), "comments")) then
call xml_AddComment(xf, getData(this))
endif
case (DOCUMENT_TYPE_NODE)
if (.not.getParameter(getDomConfig(doc), "canonical-form")) then
call xml_AddDOCTYPE(xf, getName(this))
nnm => getNotations(this)
do j = 0, getLength(nnm)-1
np => item(nnm, j)
if (getSystemId(np)=="") then
call xml_AddNotation(xf, getNodeName(np), public=getPublicId(np))
elseif (getPublicId(np)=="") then
call xml_AddNotation(xf, getNodeName(np), system=getSystemId(np))
else
call xml_AddNotation(xf, getNodeName(np), system=getSystemId(np), &
public=getPublicId(np))
endif
enddo
nnm => getEntities(this)
do j = 0, getLength(nnm)-1
np => item(nnm, j)
if (getSystemId(np)=="") then
call xml_AddInternalEntity(xf, getNodeName(np), getStringValue(np))
elseif (getPublicId(np)=="".and.getNotationName(np)=="") then
call xml_AddExternalEntity(xf, getNodeName(np), system=getSystemId(np))
elseif (getNotationName(np)=="") then
call xml_AddExternalEntity(xf, getNodeName(np), system=getSystemId(np), &
public=getPublicId(np))
elseif (getPublicId(np)=="") then
call xml_AddExternalEntity(xf, getNodeName(np), system=getSystemId(np), &
notation=getNotationName(np))
else
call xml_AddExternalEntity(xf, getNodeName(np), system=getSystemId(np), &
public=getPublicId(np), notation=getNotationName(np))
endif
enddo
do j = 1, size(xds%element_list%list)
elem => xds%element_list%list(j)
if (associated(elem%model)) &
call xml_AddElementToDTD(xf, str_vs(elem%name), str_vs(elem%model))
! Because we may have some undeclared but referenced elements
do k = 1, get_attlist_size(elem)
att_decl => get_attribute_declaration(elem, k)
call xml_AddAttlistToDTD(xf, str_vs(elem%name), &
express_attribute_declaration(att_decl))
enddo
enddo
endif
end select
'`',`
if (getNodeType(this)==ELEMENT_NODE) then
call xml_EndElement(xf, getTagName(this))
endif
'`')
end subroutine iter_dmp_xml
end module m_dom_utils