23 from ua_constants
import *
25 import xml.dom.minidom
as dom
28 from collections
import Counter
31 from ua_namespace
import opcua_node_id_t
34 logger = logging.getLogger(__name__)
44 namespaceQualifiers = []
45 referencedNamesSpaceUris = []
49 self.
targetXML = tempfile.mkstemp(prefix=os.path.basename(originXML)+
"_preProcessed-" ,suffix=
".xml")
58 if len(self.
nodeset.getElementsByTagName(
"UANodeSet")) == 0
or len(self.
nodeset.getElementsByTagName(
"UANodeSet")) > 1:
59 logger.error(self,
"Document " + self.
targetXML[1] +
" contains no or more then 1 nodeset", LOG_LEVEL_ERROR)
63 logger.debug(
"Adding new document to be preprocessed " + os.path.basename(originXML) +
" as " + self.
targetXML[1])
75 """ extractNamespaceURIs
77 minidom gobbles up <NamespaceUris></NamespaceUris> elements, without a decent
78 way to reliably access this dom2 <uri></uri> elements (only attribute xmlns= are
79 accessible using minidom). We need them for dereferencing though... This
80 function attempts to do just that.
87 line = infile.readline()
89 if "<namespaceuris>" in line.lower():
91 elif "</namespaceuris>" in line.lower():
93 nsline = nsline + line
96 nsline = nsline + line
99 ns = dom.parseString(nsline).getElementsByTagName(
"NamespaceUris")
100 for uri
in ns[0].childNodes:
101 if uri.nodeType != uri.ELEMENT_NODE:
110 analyze will gather information about the nodes and references contained in a XML File
111 to facilitate later preprocessing stages that adresss XML dependency issues
113 returns: No return value
116 ns = self.
nodeset.getElementsByTagName(
"UANodeSet")
122 for key
in ns[0].attributes.keys():
126 self.
namespaceOrder.append((int(key.replace(
"xmlns:s",
"")), re.sub(
"[A-Za-z0-9-_\.]+\.[xXsSdD]{3}$",
"",ns[0].getAttribute(key))))
129 for nd
in ns[0].childNodes:
130 if nd.nodeType != nd.ELEMENT_NODE:
132 if nd.hasAttribute(
u'NodeId'):
134 refs = nd.getElementsByTagName(
u'References')[0]
135 for ref
in refs.childNodes:
136 if ref.nodeType == ref.ELEMENT_NODE:
144 Counts the namespace IDs in all nodes of this XML and picks the most used
145 namespace as the numeric identifier of this data model.
147 returns: Integer ID of the most propable/most used namespace in this XML
150 namespaceIdGuessed = 0;
154 if not ndid[0].ns
in idDict.keys():
155 idDict[ndid[0].ns] = 1
157 idDict[ndid[0].ns] = idDict[ndid[0].ns] + 1
160 if idDict[entry] > max:
162 namespaceIdGuessed = entry
164 return namespaceIdGuessed
167 """ getReferencedNamespaceUri
169 returns an URL that hopefully corresponds to the nsId that was used to reference this model
171 return: URI string corresponding to nsId
190 if not ndid[0].ns
in deps:
191 deps.append(ndid[0].ns)
199 outline = outline.replace(rq,
"")
200 os.write(outfile, outline.encode(
'UTF-8'))
204 """ reassignReferencedNamespaceId
206 Iterates over all references in this document, find references to currentNsId and changes them to newNsId.
207 NodeIds themselves are not altered.
212 if refNd[0].ns == currentNsId:
213 refNd[1].firstChild.data = refNd[1].firstChild.data.replace(
"ns="+
str(currentNsId),
"ns="+
str(newNsId))
214 refNd[0].ns = newNsId
218 """ reassignNamespaceId
220 Iterates over all nodes in this document, find those in namespace currentNsId and changes them to newNsId.
226 ns = self.
nodeset.getElementsByTagName(
"Alias")
228 if al.nodeType == al.ELEMENT_NODE:
229 if al.hasAttribute(
"Alias"):
230 al.firstChild.data = al.firstChild.data.replace(
"ns=" +
str(currentNsId),
"ns=" +
str(newNsId))
232 logger.debug(
"Migrating nodes /w ns index " +
str(currentNsId) +
" to " +
str(newNsId))
234 if nd[0].ns == currentNsId:
237 if refNd[0].ns == currentNsId
and refNd[0] == nd[0]:
238 refNd[1].firstChild.data = refNd[1].firstChild.data.replace(
"ns="+
str(currentNsId),
"ns="+
str(newNsId))
239 refNd[0].ns = newNsId
241 nd[1].setAttribute(
u'NodeId', nd[1].getAttribute(
u'NodeId').replace(
"ns="+
str(currentNsId),
"ns="+
str(newNsId)))
246 preProcDocuments = []
262 files.append(doc.getTargetXMLName())
266 """ testModelCongruencyAgainstReferences
268 Counts how many of the nodes referencef in refs can be found in the model
271 returns: double corresponding to the percentage of hits
278 for n
in doc.containedNodes:
283 return float(found)/float(sspace)
291 if doc.getNamespaceId() == 0:
300 nsid = doc.getNamespaceId()
301 doc.reassignNamespaceId(nsid, nsidx)
303 logger.info(
"Document " + doc.originXML +
" is now namespace " +
str(nsidx))
307 """ getUsedNamespaceArrayNames
309 Returns the XML xmlns:s1 or <URI>[0] of each XML document (if contained/possible)
311 returns: dict of int:nsId -> string:url
315 uri = doc.getReferencedNamespaceUri(1)
317 uri =
"http://modeluri.not/retrievable/from/xml"
318 nsName[doc.getNamespaceId()] = doc.getReferencedNamespaceUri(1)
322 revertToStochastic = []
326 nsid = doc.getNamespaceId()
327 dependencies = doc.getNamespaceDependencies()
328 for d
in dependencies:
329 if d != nsid
and d != 0:
331 nsUri = doc.getReferencedNamespaceUri(d)
332 logger.info(
"Need a namespace referenced as " +
str(d) +
". Which hopefully is " + nsUri)
337 if tgt.getReferencedNamespaceUri(1) == nsUri:
340 if not targetDoc ==
None:
342 doc.reassignReferencedNamespaceId(d, targetDoc.getNamespaceId())
345 revertToStochastic.append((doc, d))
346 logger.warn(
"Failed to reliably identify which XML/Model " + os.path.basename(doc.originXML) +
" calls ns=" +
str(d))
348 for (doc, d)
in revertToStochastic:
349 logger.warn(
"Attempting to find stochastic match for target namespace ns=" +
str(d) +
" of " + os.path.basename(doc.originXML))
353 for ref
in doc.referencedNodes:
357 tDocId = tDoc.getNamespaceId()
366 matches.append((c, tDoc))
373 logger.warn(
"Best match (" +
str(best[1]*100) +
"%) for what " + os.path.basename(doc.originXML) +
" refers to as ns="+
str(d)+
" was " + os.path.basename(best[1].originXML))
374 doc.reassignReferencedNamespaceId(d, best[1].getNamespaceId())
376 logger.error(
"Failed to find a match for what " + os.path.basename(doc.originXML) +
" refers to as ns=" +
str(d))