import {XMLParser, type X2jOptions} from 'fast-xml-parser'; import { UAObject } from './UAObject'; import type { UABaseNode } from './UABaseNode'; import { UAVariable } from './UAVariable'; import { UAMethod } from './UAMethod'; import { NamespaceTable } from './NameSpaceTable'; import { UAModel } from './UAModel'; import { XMLElem, type IToXML } from '@/util/XmlElem'; import { UAReferenceType } from './UAReferenceType'; import { UAObjectType } from './UAObjectType'; import { UAVariableType } from './UAVariableType'; import type { AddressSpace } from './AddressSpace'; import type { IAddressSpace } from './IAddressSpace'; import { UAAlias } from './UAAlias'; export class UANodeSet implements IToXML{ constructor(public fileName: string, public models: UAModel[], public aliases: UAAlias[], public nodes: UABaseNode[], public nameSpaceTable: NamespaceTable, public xmlns: string, public xmlns_xsi: string, public xmlns_xsd: string, public lastModified: string, ) { } reIndex(nst: NamespaceTable) { //add all missing namespaces to addressspace ns table for(const value of this.nameSpaceTable.nsMap.getValues()) { nst.addUri(value); } for(const node of this.nodes) { node.reIndex(nst, this.nameSpaceTable); } } resolveReferences(nm: Map) { for(const node of this.nodes) { node.resolveReferences(nm); } } toXML(lnst: NamespaceTable, gnst: NamespaceTable): XMLElem { const xmlUANodeSet =new XMLElem('UANodeSet'); xmlUANodeSet.attr('xmlns:xsi', this.xmlns_xsi); xmlUANodeSet.attr('xmlns:xsd', this.xmlns_xsd); xmlUANodeSet.attr('xmlns', this.xmlns); xmlUANodeSet.attr('LastModified', this.lastModified); const xmlNameSpaceUris=xmlUANodeSet.add(new XMLElem('NamespaceUris')); for(let i=1;i { const xml= await (await fetch(url)).text(); const fileName= url.split('/').pop()||url return this.parse(xml, fileName, addressSpace); } static parse(xml: string, fileName: string, addressSpace: IAddressSpace): UANodeSet { const parseOptions:Partial={ ignoreAttributes: false, alwaysCreateTextNode: true, //force consistent result parseTagValue:false, //disable number detection. Otherwise string values might end up as numbers. // eslint-disable-next-line @typescript-eslint/no-unused-vars isArray: (name, jpath, isLeafNode, isAttribute):boolean => { switch(jpath) { case 'UANodeSet.NamespaceUris.Uri': case 'UANodeSet.Models.Model': case 'UANodeSet.Models.Model.RequiredModel': case 'UANodeSet.UAObject': case 'UANodeSet.UAObject.References.Reference': case 'UANodeSet.UAObject.DisplayName': case 'UANodeSet.UAObject.Description': case 'UANodeSet.UAObject.Category': case 'UANodeSet.UAObject.RolePermissions.RolePermission': case 'UANodeSet.UAObjectType': case 'UANodeSet.UAObjectType.References.Reference': case 'UANodeSet.UAObjectType.DisplayName': case 'UANodeSet.UAObjectType.Description': case 'UANodeSet.UAObjectType.Category': case 'UANodeSet.UAObjectType.RolePermissions.RolePermission': case 'UANodeSet.UAMethod': case 'UANodeSet.UAMethod.References.Reference': case 'UANodeSet.UAMethod.DisplayName': case 'UANodeSet.UAMethod.Description': case 'UANodeSet.UAMethod.Category': case 'UANodeSet.UAMethod.RolePermissions.RolePermission': case 'UANodeSet.UAVariable': case 'UANodeSet.UAVariable.References.Reference': case 'UANodeSet.UAVariable.DisplayName': case 'UANodeSet.UAVariable.Description': case 'UANodeSet.UAVariable.Category': case 'UANodeSet.UAVariable.RolePermissions.RolePermission': case 'UANodeSet.UAVariableType': case 'UANodeSet.UAVariableType.References.Reference': case 'UANodeSet.UAVariableType.DisplayName': case 'UANodeSet.UAVariableType.Description': case 'UANodeSet.UAVariableType.Category': case 'UANodeSet.UAVariableType.RolePermissions.RolePermission': case 'UANodeSet.UAReferenceType': case 'UANodeSet.UAReferenceType.References.Reference': case 'UANodeSet.UAReferenceType.DisplayName': case 'UANodeSet.UAReferenceType.Description': case 'UANodeSet.UAReferenceType.Category': case 'UANodeSet.UAReferenceType.RolePermissions.RolePermission': return true; default: return false; } } } const parser = new XMLParser(parseOptions); const xmlObj = parser.parse(xml); const xmlAliases=xmlObj['UANodeSet']['Aliases']||[]; const aliases: UAAlias[]=[]; for(const xmlAlias of xmlAliases.Alias) { aliases.push(UAAlias.fromXML(xmlAlias)); } const models: UAModel[]=[]; const xmlModels=xmlObj['UANodeSet']['Models']||[]; for(const xmlModel of xmlModels.Model) { models.push(UAModel.fromXML(xmlModel)); } const nodes:UABaseNode[]=[]; const xmlObjects=xmlObj['UANodeSet']['UAObject']||[]; for(const xmlObject of xmlObjects) { nodes.push(UAObject.fromXML(xmlObject, addressSpace)); } const xmlVariables=xmlObj['UANodeSet']['UAVariable']||[]; for(const xmlVariable of xmlVariables) { nodes.push(UAVariable.fromXML(xmlVariable, addressSpace)); } const xmlMethods=xmlObj['UANodeSet']['UAMethod']||[]; for(const xmlMethod of xmlMethods) { nodes.push(UAMethod.fromXML(xmlMethod, addressSpace)); } const xmlReferenceTypes=xmlObj['UANodeSet']['UAReferenceType']||[]; for(const xmlReferenceType of xmlReferenceTypes) { nodes.push(UAReferenceType.fromXML(xmlReferenceType, addressSpace)); } const xmlObjectTypes=xmlObj['UANodeSet']['UAObjectType']||[]; for(const xmlObjectType of xmlObjectTypes) { nodes.push(UAObjectType.fromXML(xmlObjectType, addressSpace)); } const xmlVariableTypes=xmlObj['UANodeSet']['UAVariableType']||[]; for(const xmlVariableType of xmlVariableTypes) { nodes.push(UAVariableType.fromXML(xmlVariableType, addressSpace)); } const uaNamespaceUris=xmlObj['UANodeSet']['NamespaceUris']||[]; const nst=new NamespaceTable(); for(const nsUri of uaNamespaceUris['Uri']||[]) { nst.addUri(nsUri['#text']) } return new UANodeSet(fileName, models, aliases, nodes, nst, xmlObj['UANodeSet']['@_xmlns'], xmlObj['UANodeSet']['@_xmlns:xsi'], xmlObj['UANodeSet']['@_xmlns:xsd'], xmlObj['UANodeSet']['@_LastModified']); } }