OpenEnergyTools / scl-lib

5 stars 4 forks source link

tIED: Handling of namespaces from the imported IED #54

Open danyill opened 1 year ago

danyill commented 1 year ago

Currently our insertIED doesn't handle namespaces correctly.

Rather than being declared on the document they are "long-hand" against every instance:

For instance:

<?xml version="1.0" encoding="UTF-8"?><SCL xmlns="http://www.iec.ch/61850/2003/SCL" version="2007" revision="B" release="4">
    <Header id="test_comms"/>
<Communication><SubNetwork name="Default_subnet">
      <ConnectedAP iedName="SIEMENS_7UT85_02" apName="F" redProt="prp">
        <Address>
          <P xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="tP_IP" type="IP">10.124.136.247</P>
          <P xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="tP_IP-SUBNET" type="IP-SUBNET">255.255.255.0</P>
          <P xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="tP_IP-GATEWAY" type="IP-GATEWAY">10.124.136.1</P>
          <P type="OSI-AP-Title">1,3,9999,23</P>
          <P type="OSI-AE-Qualifier">23</P>
          <P type="OSI-PSEL">00000001</P>
          <P type="OSI-SSEL">0001</P>
          <P type="OSI-TSEL">0001</P>
        </Address>
        <GSE ldInst="HVCB" cbName="Ctl_1">
          <Address>
            <P xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="tP_VLAN-ID" type="VLAN-ID">3EE</P>
            <P xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="tP_VLAN-PRIORITY" type="VLAN-PRIORITY">4</P>
            <P xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="tP_MAC-Address" type="MAC-Address">01-0C-CD-01-01-0E</P>
            <P xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="tP_APPID" type="APPID">0006</P>
          </Address>

What I've done previously to resolve this (without using the Edit API) is:

/**
 * Transfer namespace definitions from one element to another
 * @param destElement - Element to transfer namespaces to
 * @param sourceElement  - Element to transfer namespaces from
 */
function updateNamespaces(destElement: Element, sourceElement: Element) {
  Array.prototype.slice
    .call(sourceElement.attributes)
    .filter(attr => attr.name.startsWith('xmlns:'))
    .filter(attr => !destElement.hasAttribute(attr.name))
    .forEach(attr => {
      destElement.setAttributeNS(
        'http://www.w3.org/2000/xmlns/',
        attr.name,
        attr.value
      );
    });
}

However I think we could use an update edit to do this now.

I think we'd transfer each namespace definition and between the IED being inserted and the SCL document it is being inserted into. I'm not sure but I think setAttributeNS will handle namespace collisions as well.

JakobVogelsang commented 1 year ago

In the above example, you are speaking about the xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" in the P element right?

danyill commented 1 year ago

Yes, but it applies to any namespace associated with the imported IED.

On Sat, 30 Sep 2023, 16:51 Jakob Vogelsang, @.***> wrote:

In the above example, you are speaking about the xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance" in the P element right?

— Reply to this email directly, view it on GitHub https://github.com/OpenEnergyTools/scl-lib/issues/54#issuecomment-1741846812, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAFEXX5ME6XYHUA6BO6METLX5BZ3HANCNFSM6AAAAAA5MVM2WQ . You are receiving this because you authored the thread.Message ID: @.***>

JakobVogelsang commented 1 year ago

I am asking because in particular the above-mentioned I have always seen on the element. I think there was something about it that it has too. We should research that.

danyill commented 1 year ago

I am asking because in particular the above-mentioned I have always seen on the element. I think there was something about it that it has too. We should research that.

That would surprise me because it would only be one way of providing a valid reference to the namespace.

I had a look through IEC 61850-6-2 and found that it commonly uses the short prefix:

image

Here is another example: Archive.zip

I start with test_comms.scd, I insert the SEL device XAT_SEL-487E-5_StandardDesign.ICD with the result of test_comms (26).scd with the result that all namespaces are fully qualified:

    <Private type="SEL_IedInfo">
      <esel:ModelNumber xmlns:esel="http://www.selinc.com/2006/61850">SEL-487E-5S</esel:ModelNumber>
      <esel:ModelVersionMin xmlns:esel="http://www.selinc.com/2006/61850">R404</esel:ModelVersionMin>
      <esel:ClassFileVersion xmlns:esel="http://www.selinc.com/2006/61850">007</esel:ClassFileVersion>
      <esel:ClassFileDescription xmlns:esel="http://www.selinc.com/2006/61850" default="false">487E-5S - Sampled Values Subscriber R404-V0 or higher (Ed. 2 support, Controllable mod/beh)</esel:ClassFileDescription>
      <esel:IcdFilePath xmlns:esel="http://www.selinc.com/2006/61850">C:\XAT_SEL-487E-5_StandardDesign_Production_mod.ICD</esel:IcdFilePath>
    </Private>
    <Private type="SEL_IedComm">
      <esel:MMS xmlns:esel="http://www.selinc.com/2006/61850" inactivityTimeout="900"/>
    </Private>
    <Private type="SEL_IedResources">
      <esel:InDigitals xmlns:esel="http://www.selinc.com/2006/61850">
        <esel:InBits format="VB{0:D3}" min="1" max="256"/>
      </esel:InDigitals>
      <esel:InAnalogs xmlns:esel="http://www.selinc.com/2006/61850">
        <esel:InFloat format="RA{0:D3}" min="1" max="256"/>
      </esel:InAnalogs>
      <esel:GooseRxFilter xmlns:esel="http://www.selinc.com/2006/61850" APPID="true" goCbRef="true" datSetRef="true" goId="true" confRev="true" ndsCom="true" test="true"/>
      <esel:GooseTx xmlns:esel="http://www.selinc.com/2006/61850" minMaxTime="4"/>
      <esel:GooseTx xmlns:esel="http://www.selinc.com/2006/61850" maxBoolData="512"/>
      <esel:SVRx xmlns:esel="http://www.selinc.com/2006/61850" max="7"/>
      <esel:SVRxAnalogChannels xmlns:esel="http://www.selinc.com/2006/61850" max="24"/>
      <esel:Reports xmlns:esel="http://www.selinc.com/2006/61850" maxDataSetSize="8000"/>
      <esel:System xmlns:esel="http://www.selinc.com/2006/61850" mmsAuthenticationSupported="true"/>
      <esel:System xmlns:esel="http://www.selinc.com/2006/61850" controllableModeSupported="true"/>
    </Private>
JakobVogelsang commented 9 months ago

Do you have a proposal how to resolve this issue? I feel we had a discussion about this already. @danyill

danyill commented 9 months ago

I think we need a helper function to scan namespaces and add them to the SCL element which is what Part 6 recommends. I can't help wondering if this isn't at some level a "core" function - spot an edit which includes a namespaced element and if it's not already there, add it. Perhaps we need some input from @ca-d?

ca-d commented 7 months ago

I think we might add some smart logic to the Edit API within open-scd-core to handle these cases. I'm envisaging something like:

  1. If the Inserted Node has node.ownerDocument === this.doc, we're done.
  2. If the Update contains no namespaced attributes, we're done.
  3. For any namespaced attributes in the Update or in the Inserted Node's DOM tree:
    1. Check if we already have a namespace prefix defined using node.ownerDocument.documentElement.lookupPrefix(namespaceURI) .
    2. If so, add Updates that exchange all namespace prefixes for the prefix that's already defined on the root element. We're done.
    3. Else, add the first prefix that's found to the root element, go back to step 3.i

What do you think about this procedure?

danyill commented 7 months ago

It seems desirable to me. Is it too expensive to recurse through all nodes as a matter of course though? I am thinking especially of Insert and Remove edits.

If that caused a significant performance penalty then having a "don't worry I know what I'm doing" flag might be a good idea.

On Wed, 3 Apr 2024, 01:00 cad, @.***> wrote:

I think we might add some smart logic to the Edit API within open-scd-core to handle these cases. I'm envisaging something like:

  1. If the Inserted Node has node.ownerDocument === this.doc, we're done.
  2. If the Update contains no namespaced attributes, we're done.
  3. For any namespaced attributes in the Update or in the Inserted Node's DOM tree:
    1. Check if we already have a namespace prefix defined using node.ownerDocument.documentElement.lookupPrefix(namespaceURI) .
    2. If so, add Updates that exchange all namespace prefixes for the prefix that's already defined on the root element. We're done.
    3. Else, add the first prefix that's found to the root element, go back to step 3.i

What do you think about this procedure?

— Reply to this email directly, view it on GitHub https://github.com/OpenEnergyTools/scl-lib/issues/54#issuecomment-2031855291, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAFEXX536KTLWD3XICKU5P3Y3KMXDAVCNFSM6AAAAAA5MVM2WSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDAMZRHA2TKMRZGE . You are receiving this because you were mentioned.Message ID: @.***>

ca-d commented 7 months ago

In the above procedure, we would recurse through all nodes only in the case of Insert actions containing a node from a foreign document. In the case of Remove, there's nothing that needs doing, and we assume that in the case of nodes from this.doc all the relevant namespace prefixes have already been declared on the root element.

Do you think we need to cover more cases than these?

danyill commented 7 months ago

No that seems complete, and even if there is a cost, we must not (not ever) sacrifice correctness for performance...

So yes let's do it!

I should note that we've found at least two ICT tools which don't correctly manage namespaces so I think it's important to handle it and I am especially pleased that core should handle this. It shouldn't be something a plugin author has to worry about and that's what I like about your proposal 😉👍

On Wed, 3 Apr 2024, 22:43 cad, @.***> wrote:

In the above procedure, we would recurse through all nodes only in the case of Insert actions containing a node from a foreign document. In the case of Remove, there's nothing that needs doing, and we assume that in the case of nodes from this.doc all the relevant namespace prefixes have already been declared on the root element.

Do you think we need to cover more cases than these?

— Reply to this email directly, view it on GitHub https://github.com/OpenEnergyTools/scl-lib/issues/54#issuecomment-2034074661, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAFEXX2TDFNGGLIMUXRQ6PLY3PFNNAVCNFSM6AAAAAA5MVM2WSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDAMZUGA3TINRWGE . You are receiving this because you were mentioned.Message ID: @.***>