Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions tDataTypeTemplates/nsdToJson.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import {
nsd7420,
nsd81,
} from "../foundation/codecomponents/nsds.js";
import { lnClass74, lnClassData } from "./nsdToJson/testNsdJson.js";
import { cdcData, lnClass74, lnClassData } from "./nsdToJson/testNsdJson.js";

import { nsdToJson } from "./nsdToJson.js";
import { nsdToJson, supportedCdc } from "./nsdToJson.js";

const doc72 = new DOMParser().parseFromString(nsd72, "application/xml");
const doc73 = new DOMParser().parseFromString(nsd73, "application/xml");
Expand All @@ -21,6 +21,9 @@ describe("NSD to Json parsing function", () => {
it("return undefined for invalid ln class", () =>
expect(nsdToJson("invalid")).to.be.undefined);

it("return undefined for unsupported CDC", () =>
expect(nsdToJson("ENS")).to.be.undefined);

it("returns object that compares well to static 7-4 ln classes", async () => {
lnClass74.forEach((lnClass) => {
const data = nsdToJson(lnClass)!;
Expand All @@ -32,6 +35,17 @@ describe("NSD to Json parsing function", () => {
});
}).timeout(10000);

it("returns object that compares well to static 7-3 ln classes", async () => {
supportedCdc.forEach((cdc) => {
const data = nsdToJson(cdc)!;
const commonDataClass = cdcData[cdc];

Object.keys(commonDataClass).forEach((key) => {
expect(data[key]).to.deep.equal(commonDataClass[key]);
});
});
}).timeout(10000);

it("returns object that compares well to static 7-420 classes", async () => {
const data = nsdToJson("DSTK");
expect(data).to.not.be.undefined;
Expand Down
154 changes: 117 additions & 37 deletions tDataTypeTemplates/nsdToJson.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,48 @@ type CdcDescription = {

export type LNodeDescription = Record<string, CdcDescription>;

export const supportedCdc = [
"ACD",
"ACT",
"APC",
"ASG",
"BAC",
"BCR",
"BSC",
"CMV",
"DEL",
"DPC",
"DPL",
"HDEL",
"HMV",
"HST",
"HWYE",
"INC",
"INS",
"ISC",
"LPL",
"MV",
"ORG",
"ORS",
"SAV",
"SEC",
"SEQ",
"SPC",
"SPG",
"SPS",
"TCS",
"TSG",
"VSG",
"VSS",
"WYE",
] as const;
const cdcTag = new Set<string>(supportedCdc);
export type SCLTag = (typeof supportedCdc)[number];

export function isSupportedCdc(cdc: string): cdc is SCLTag {
return cdcTag.has(cdc);
}

export type NameSpaceDescription = {
"72"?: XMLDocument;
"73"?: XMLDocument;
Expand All @@ -123,7 +165,7 @@ const defaultDoc81 = new DOMParser().parseFromString(nsd81, "application/xml");

/** A utility function that returns a JSON containing the structure of a logical node class
* as described in the IEC 61850-7-4 and IEC 61850-7-420 as JSON
* @param lnClass the logical node class to be constructed
* @param lnClassOrCdc the logical node class to be constructed
* @param nsds user defined NSD files defaulting to
* 8-1: 2003A2
* 7-4: 2007B3
Expand All @@ -133,19 +175,13 @@ const defaultDoc81 = new DOMParser().parseFromString(nsd81, "application/xml");
* @returns A JSON object represeting NSD information of a logical node
*/
export function nsdToJson(
lnClass: string,
lnClassOrCdc: string,
nsds?: NameSpaceDescription,
): LNodeDescription | undefined {
): LNodeDescription | CdcChildren | undefined {

const doc74 = nsds && nsds["74"] ? nsds["74"] : defaultDoc74;
const doc7420 = nsds && nsds["7420"] ? nsds["7420"] : defaultDoc7420;
const nsdLnClass74 = doc74.querySelector(`LNClass[name="${lnClass}"]`);
const nsdLnClass7420 = doc7420.querySelector(`LNClass[name="${lnClass}"]`);

const nsdLnClass = nsdLnClass74 || nsdLnClass7420;
if (!nsdLnClass) return undefined;

const lnClassJson: LNodeDescription = {};


function getServiceConstructedAttributes(
serviceDataAttribute: Element,
): Element[] {
Expand All @@ -161,18 +197,23 @@ export function nsdToJson(
);
}

function getServiceDataAttributes(dataObject: Element): Element[] {
function getServiceDataAttributesType(type : string | null): Element[] {
const doc81 = nsds && nsds["81"] ? nsds["81"] : defaultDoc81;

const type = dataObject.getAttribute("type");
return Array.from(
doc81
.querySelector(`ServiceCDCs > ServiceCDC[cdc="${type}"]`)
?.querySelectorAll("ServiceDataAttribute") ?? [],
);
}

function getSubDataAttributesType(type: string): Element[] {
function getServiceDataAttributes(dataObject: Element): Element[] {
const type = dataObject.getAttribute("type");

return getServiceDataAttributesType(type);
}

function getSubDataAttributesType(type: string | null): Element[] {
const doc73 = nsds && nsds["73"] ? nsds["73"] : defaultDoc73;
const doc72 = nsds && nsds["72"] ? nsds["72"] : defaultDoc72;

Expand All @@ -190,27 +231,14 @@ export function nsdToJson(
}

function getSubDataAttributes(dataAttribute: Element): Element[] {
const doc73 = nsds && nsds["73"] ? nsds["73"] : defaultDoc73;
const doc72 = nsds && nsds["72"] ? nsds["72"] : defaultDoc72;

const type = dataAttribute.getAttribute("type");
return Array.from(
doc73
.querySelector(`ConstructedAttribute[name="${type}"]`)
?.querySelectorAll(":scope > SubDataAttribute") ?? [],
).concat(
Array.from(
doc72
.querySelector(`ConstructedAttribute[name="${type}"]`)
?.querySelectorAll(":scope > SubDataAttribute") ?? [],
),
);

return getSubDataAttributesType(type)
}

function getDataAttributes(dataObject: Element): Element[] {
function getDataAttributesType(type:string|null): Element[] {
const doc73 = nsds && nsds["73"] ? nsds["73"] : defaultDoc73;

const type = dataObject.getAttribute("type");
if (
["CSG", "CURVE", "ENG", "ING", "ASG", "SPG", "TSG", "VSG"].includes(
`${type}`,
Expand All @@ -228,16 +256,28 @@ export function nsdToJson(
);
}

function getSubDataObjects(dataObject: Element): Element[] {
const doc73 = nsds && nsds["73"] ? nsds["73"] : defaultDoc73;
function getDataAttributes(dataObject: Element): Element[] {
const type = dataObject.getAttribute("type");

return getDataAttributesType(type);
}

function getSubDataObjectsType(type: string | null): Element[] {
const doc73 = nsds && nsds["73"] ? nsds["73"] : defaultDoc73;

return Array.from(
doc73
.querySelector(`CDC[name="${type}"]`)
?.querySelectorAll("SubDataObject") ?? [],
);
}

function getSubDataObjects(dataObject: Element): Element[] {
const type = dataObject.getAttribute("type");

return getSubDataObjectsType(type)
}

function getDataObjects(lnClass: Element): Element[] {
const baseClass = lnClass.ownerDocument.querySelector(
`AbstractLNClass[name="${lnClass.getAttribute("base")}"]`,
Expand Down Expand Up @@ -579,11 +619,51 @@ export function nsdToJson(
return data;
}

getDataObjects(nsdLnClass).forEach((dataObject) => {
const name = dataObject.getAttribute("name")!;
function CdcChildren(type: string): CdcChildren {

const children: CdcChildren = {};
getSubDataObjectsType(type).forEach((dataObject) => {
const name = dataObject.getAttribute("name")!;

children[name] = nsdDataObject(dataObject);
});

getDataAttributesType(type).forEach((dataAttribute) => {
const name = dataAttribute.getAttribute("name")!;

lnClassJson[name] = nsdDataObject(dataObject);
});
children[name] = nsdDataAttribute(
dataAttribute,
undefined,
undefined,
);
});

getServiceDataAttributesType(type).forEach((serviceDataAttribute) => {
const name = serviceDataAttribute.getAttribute("name")!;

children[name] = nsdServiceDataAttribute(serviceDataAttribute);
});

return children;
}

if (lnClassOrCdc === undefined) return;
else if (isSupportedCdc(lnClassOrCdc))
return CdcChildren(lnClassOrCdc);
else {
const nsdLnClass74 = doc74.querySelector(`LNClass[name="${lnClassOrCdc}"]`);
const nsdLnClass7420 = doc7420.querySelector(`LNClass[name="${lnClassOrCdc}"]`);

const nsdLnClass = nsdLnClass74 || nsdLnClass7420;
if (!nsdLnClass) return undefined;

const lnClassJson: LNodeDescription = {};
getDataObjects(nsdLnClass).forEach((dataObject) => {
const name = dataObject.getAttribute("name")!;

lnClassJson[name] = nsdDataObject(dataObject);
});

return lnClassJson;
return lnClassJson
}
}
24 changes: 1 addition & 23 deletions tDataTypeTemplates/nsdToJson/testJson/ARIS.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,13 @@
import { acdChildren } from "./ACD.js";
import { actChildren } from "./ACT.js";
import { apcChildren } from "./APC.js";
import { asgChildren } from "./ASG.js";
import { bacChildren } from "./BAC.js";
import { bcrChildren } from "./BCR.js";
import { bscChildren } from "./BSC.js";
import { cmvChildren } from "./CMV.js";
import { delChildren } from "./DEL.js";
import { dpcChildren } from "./DPC.js";
import { dplChildren } from "./DPL.js";
import { hdelChildren } from "./HDEL.js";
import { hmvChildren } from "./HMV.js";
import { hstChildren } from "./HST.js";
import { hwyeChildren } from "./HWYE.js";
import { incChildren } from "./INC.js";
import { ingChildren } from "./ING.js";
import { insChildren } from "./INS.js";
import { lplChildren } from "./LPL.js";
import { mvChildren } from "./MV.js";
import { orgChildren } from "./ORG.js";
import { orsChildren } from "./ORS.js";
import { savChildren } from "./SAV.js";
import { secChildren } from "./SEC.js";
import { seqChildren } from "./SEQ.js";
import { spcChildren } from "./SPC.js";
import { spsChildren } from "./SPS.js";
import { tscChildren } from "./TSC.js";
import { tsgChildren } from "./TSG.js";
import { vsgChildren } from "./VSG.js";
import { vssChildren } from "./VSS.js";
import { wyeChildren } from "./WYE.js";

export const aris = {
Auto: {
tagName: "DataObject",
Expand Down
6 changes: 3 additions & 3 deletions tDataTypeTemplates/nsdToJson/testJson/FSCH.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { orgChildren } from "./ORG.js";
import { spcChildren } from "./SPC.js";
import { spsChildren } from "./SPS.js";
import { spgChildren } from "./SPG.js";
import { tscChildren } from "./TSC.js";
import { tcsChildren } from "./TCS.js";
import { tsgChildren } from "./TSG.js";

export const fsch = {
Expand Down Expand Up @@ -1551,7 +1551,7 @@ export const fsch = {
descID: "IEC61850_7_4.LNGroupF::FSCH.ActStrTm.desc",
presCond: "O",
dsPresCond: "na",
children: tscChildren,
children: tcsChildren,
},
NxtStrTm: {
tagName: "DataObject",
Expand All @@ -1561,7 +1561,7 @@ export const fsch = {
mandatory: true,
presCond: "M",
dsPresCond: "na",
children: tscChildren,
children: tcsChildren,
},
SchdEnaErr: {
tagName: "DataObject",
Expand Down
26 changes: 1 addition & 25 deletions tDataTypeTemplates/nsdToJson/testJson/IARC.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,11 @@
import { acdChildren } from "./ACD.js";
import { actChildren } from "./ACT.js";
import { apcChildren } from "./APC.js";
import { asgChildren } from "./ASG.js";
import { bacChildren } from "./BAC.js";
import { bcrChildren } from "./BCR.js";
import { bscChildren } from "./BSC.js";
import { cmvChildren } from "./CMV.js";
import { delChildren } from "./DEL.js";
import { dpcChildren } from "./DPC.js";
import { dplChildren } from "./DPL.js";
import { hdelChildren } from "./HDEL.js";
import { hmvChildren } from "./HMV.js";
import { hstChildren } from "./HST.js";
import { hwyeChildren } from "./HWYE.js";
import { incChildren } from "./INC.js";
import { ingChildren } from "./ING.js";
import { insChildren } from "./INS.js";
import { lplChildren } from "./LPL.js";
import { mvChildren } from "./MV.js";
import { orgChildren } from "./ORG.js";
import { orsChildren } from "./ORS.js";
import { savChildren } from "./SAV.js";
import { secChildren } from "./SEC.js";
import { seqChildren } from "./SEQ.js";
import { spcChildren } from "./SPC.js";
import { spsChildren } from "./SPS.js";
import { tscChildren } from "./TSC.js";
import { tsgChildren } from "./TSG.js";
import { vsgChildren } from "./VSG.js";
import { vssChildren } from "./VSS.js";
import { wyeChildren } from "./WYE.js";

export const iarc = {
EEName: {
tagName: "DataObject",
Expand Down
Loading