Diff of /PlcOpenXmlLadderToAsciiLadder.py [000000] .. [9bc435]  Maximize  Restore

Switch to side-by-side view

--- a
+++ b/PlcOpenXmlLadderToAsciiLadder.py
@@ -0,0 +1,275 @@
+# PlcOpenXmlLadderToAsciiLadder
+import sys
+import xml.dom.minidom
+
+def howCloseAmIToLeftPowerRail(num, ladder, element):
+    # Function to work out how close an element is to the left...
+    # element is a dom element of contact, coil, block
+    # ladder is the whole ladder
+    # num is the current distance, initially zero
+    if element.tagName == "contact" or element.tagName == "coil" or element.tagName == "leftPowerRail":
+        _num = num + 1
+    else: # "block", maybe "execute"?
+        _num = num + 3
+    highestnum = _num
+    for conny in element.getElementsByTagName("connection"):
+        for _elly in ladder.childNodes:
+            if _elly.nodeType != _elly.TEXT_NODE:
+                if _elly.getAttribute("localId") == conny.getAttribute("refLocalId"):
+                    # pass how close this element is
+                    connysNum = howCloseAmIToLeftPowerRail(_num, ladder, _elly)
+        if connysNum > highestnum:
+            highestnum = connysNum
+    return highestnum
+
+# main
+if len(sys.argv) == 2:
+    filepathin = sys.argv[1]
+    print(filepathin)
+    doc = xml.dom.minidom.parse(filepathin)
+    # get the first (currently only) entire declaration header as a string
+    declarationheader = doc.getElementsByTagName("InterfaceAsPlainText")[0].getElementsByTagName("xhtml")[0].childNodes[0].data
+    
+    # get the first (currently only) ladder element
+    ladder = doc.getElementsByTagName("LD")[0]
+    widthOfLadder = 4 # will grow by itself if the ladder needs it
+    foundANewLabel = False
+    networkNumber = 0
+    rowId = 0
+  
+    gridladder = xml.dom.minidom.Document()
+    gridladder.appendChild(gridladder.createElement("gridLD"))
+  
+    for elly in ladder.childNodes:
+        #Close a branch
+        #     <contact>
+        #        <connectionPointIn>
+        #          <connection refLocalId="39" />
+        #          <connection refLocalId="40" />
+        #        </connectionPointIn>
+        #Open a branch
+        #      <contact >        
+        #        <connectionPointIn>
+        #          <connection refLocalId="0" />
+        #        </connectionPointIn>
+        #      </contact>
+        #      <contact >
+        #        <connectionPointIn>
+        #          <connection refLocalId="0" />
+        #        </connectionPointIn>
+        #leftPowerRail
+        #comment
+        #label
+        if elly.nodeName == "label":
+            print(elly.getAttribute("label"))
+            # create new <row>, add this label to the zeroth column
+            networkNumber += 1
+            gridladder.firstChild.appendChild(gridladder.createElement("row"))
+            gridladder.firstChild.lastChild.setAttribute("rowId",str(rowId))
+            rowId += 1
+            gridladder.firstChild.lastChild.appendChild(gridladder.createElement("Column"))
+            gridladder.firstChild.lastChild.lastChild.setAttribute("columnId","0")
+            gridladder.firstChild.lastChild.lastChild.setAttribute("networkId",str(networkNumber))
+            gridladder.firstChild.lastChild.lastChild.setAttribute("label",elly.getAttribute("label"))
+            foundANewLabel = True
+        #vendorElement  (both new network and parallel branches)
+        if elly.nodeName == "vendorElement":
+            if elly.getElementsByTagName("ElementType").length > 0:
+                print("NewNetwork")
+                if foundANewLabel:# already found a label
+                    foundANewLabel = False
+                else:
+                    networkNumber += 1
+                    gridladder.firstChild.appendChild(gridladder.createElement("row"))
+                    gridladder.firstChild.lastChild.setAttribute("rowId",str(rowId))
+                    rowId += 1
+                    
+                    gridladder.firstChild.lastChild.appendChild(gridladder.createElement("Column"))
+                    gridladder.firstChild.lastChild.lastChild.setAttribute("columnId","0")
+                    gridladder.firstChild.lastChild.lastChild.setAttribute("networkId",str(networkNumber))
+            elif elly.getElementsByTagName("ParallelBranch"):
+                print("New ParallelBranch Short Circuit")
+        #inVariable (these are your inputs to blocks)
+        if elly.nodeName == "inVariable":
+            print("NewInvariable")
+        #block (FB, F etc)
+        if elly.nodeName == "block":
+            print("NewBlock")
+            mydistance = howCloseAmIToLeftPowerRail(0,ladder,elly)
+            if mydistance > widthOfLadder:
+                widthOfLadder = mydistance
+  
+            if elly.getElementsByTagName("connection")[0].getAttribute("refLocalId") == "0":
+                # that means it's leftmost object
+                if gridladder.firstChild.lastChild.lastChild.getAttribute("columnId") != "0":
+                    # that means we parallel branch and need a new row
+                    gridladder.firstChild.appendChild(gridladder.createElement("row"))
+                    gridladder.firstChild.lastChild.setAttribute("rowId",str(rowId))
+                    rowId += 1
+                gridladder.firstChild.lastChild.appendChild(gridladder.createElement("Column"))
+                gridladder.firstChild.lastChild.lastChild.setAttribute("columnId","1")
+                gridladder.firstChild.lastChild.lastChild.setAttribute("localId",elly.getAttribute("localId"))
+                gridladder.firstChild.lastChild.lastChild.setAttribute("width","3")
+            else: # that means it points behind another object
+                highestRowId = "65535"
+                widestColumn = "0"
+                for ellysUpstream in elly.getElementsByTagName("connection"):
+                    # may be more than one upstream. 
+                    # The first downstream will be in the highest row of the upstream and one column back from the furthest back upstream
+                    ellysUpstreamId = ellysUpstream.getAttribute("refLocalId")
+                    for gridellys in gridladder.firstChild.getElementsByTagName("Column"):
+                        if gridellys.getAttribute("localId") == ellysUpstreamId:
+                            if highestRowId > gridellys.parentNode.getAttribute("rowId"):
+                                highestRowId = gridellys.parentNode.getAttribute("rowId")
+                                highestRow = gridellys.parentNode
+                            widestColumn = max(widestColumn, str(int(gridellys.getAttribute("columnId")) + int(gridellys.getAttribute("width"))))
+                # Is there anyone at that RowColumn?
+                someoneIsThereAlready = False
+                for existingColumns in highestRow.getElementsByTagName("Column"):
+                    if existingColumns.getAttribute("columnId") >= widestColumn:
+                        someoneIsThereAlready = True
+                if not someoneIsThereAlready :
+                    highestRow.appendChild(gridladder.createElement("Column"))
+                    highestRow.lastChild.setAttribute("columnId",widestColumn)
+                    highestRow.lastChild.setAttribute("localId",elly.getAttribute("localId"))
+                    highestRow.lastChild.setAttribute("width","3")
+                # TODO Do something else if someone is already there
+                # TODO You will have to flag that it is parallel
+        #contact
+        if elly.nodeName == "contact":
+            if elly.getAttribute("negated") == "true":
+                print("NewNegatedContact")
+            else:
+                print("NewContact")
+  
+            mydistance = howCloseAmIToLeftPowerRail(0,ladder,elly)
+            if mydistance > widthOfLadder:
+                widthOfLadder = mydistance
+  
+            if elly.getElementsByTagName("connection")[0].getAttribute("refLocalId") == "0":
+                # that means it's leftmost object
+                if gridladder.firstChild.lastChild.lastChild.getAttribute("columnId") != "0":
+                    # that means we parallel branch and need a new row
+                    gridladder.firstChild.appendChild(gridladder.createElement("row"))
+                    gridladder.firstChild.lastChild.setAttribute("rowId",str(rowId))
+                    rowId += 1
+                gridladder.firstChild.lastChild.appendChild(gridladder.createElement("Column"))
+                gridladder.firstChild.lastChild.lastChild.setAttribute("columnId","1")
+                gridladder.firstChild.lastChild.lastChild.setAttribute("localId",elly.getAttribute("localId"))
+                gridladder.firstChild.lastChild.lastChild.setAttribute("width","1")
+            else: # that means it points behind another object
+                highestRowId = "65535"
+                widestColumn = "0"
+                for ellysUpstream in elly.getElementsByTagName("connection"):
+                    # may be more than one upstream. 
+                    # The first downstream will be in the highest row of the upstream and one column back from the furthest back upstream
+                    ellysUpstreamId = ellysUpstream.getAttribute("refLocalId")
+                    for gridellys in gridladder.firstChild.getElementsByTagName("Column"):
+                        if gridellys.getAttribute("localId") == ellysUpstreamId:
+                            if highestRowId > gridellys.parentNode.getAttribute("rowId"):
+                                highestRowId = gridellys.parentNode.getAttribute("rowId")
+                                highestRow = gridellys.parentNode
+                            widestColumn = max(widestColumn, str(int(gridellys.getAttribute("columnId")) + int(gridellys.getAttribute("width"))))
+                # Is there anyone at that RowColumn?
+                someoneIsThereAlready = False
+                for existingColumns in highestRow.getElementsByTagName("Column"):
+                    if existingColumns.getAttribute("columnId") >= widestColumn:
+                        someoneIsThereAlready = True
+                if not someoneIsThereAlready :
+                    highestRow.appendChild(gridladder.createElement("Column"))
+                    highestRow.lastChild.setAttribute("columnId",widestColumn)
+                    highestRow.lastChild.setAttribute("localId",elly.getAttribute("localId"))
+                    highestRow.lastChild.setAttribute("width","1")
+                # TODO Do something else if someone is already there
+                # TODO You will have to flag that it is parallel
+
+
+  
+        #coil
+        if elly.nodeName == "coil":
+            if elly.getAttribute("storage") == "none":
+                print("NewCoil")
+            elif elly.getAttribute("storage") == "set":
+                print("NewSetCoil")
+            elif elly.getAttribute("storage") == "reset":
+                print("NewResetCoil")
+            
+            mydistance = howCloseAmIToLeftPowerRail(0,ladder,elly)
+            if mydistance > widthOfLadder:
+                widthOfLadder = mydistance
+  
+            if elly.getElementsByTagName("connection")[0].getAttribute("refLocalId") == "0":
+                # that means it's leftmost object
+                if gridladder.firstChild.lastChild.lastChild.getAttribute("columnId") != "0":
+                    # that means we parallel branch and need a new row
+                    gridladder.firstChild.appendChild(gridladder.createElement("row"))
+                    gridladder.firstChild.lastChild.setAttribute("rowId",str(rowId))
+                    rowId += 1
+                gridladder.firstChild.lastChild.appendChild(gridladder.createElement("Column"))
+                gridladder.firstChild.lastChild.lastChild.setAttribute("columnId","1")
+                gridladder.firstChild.lastChild.lastChild.setAttribute("localId",elly.getAttribute("localId"))
+                gridladder.firstChild.lastChild.lastChild.setAttribute("width","1")
+            else: # that means it points behind another object
+                highestRowId = "65535"
+                widestColumn = "0"
+                for ellysUpstream in elly.getElementsByTagName("connection"):
+                    # may be more than one upstream. 
+                    # The first downstream will be in the highest row of the upstream and one column back from the furthest back upstream
+                    ellysUpstreamId = ellysUpstream.getAttribute("refLocalId")
+                    for gridellys in gridladder.firstChild.getElementsByTagName("Column"):
+                        if gridellys.getAttribute("localId") == ellysUpstreamId:
+                            if highestRowId > gridellys.parentNode.getAttribute("rowId"):
+                                highestRowId = gridellys.parentNode.getAttribute("rowId")
+                                highestRow = gridellys.parentNode
+                            widestColumn = max(widestColumn, str(int(gridellys.getAttribute("columnId")) + int(gridellys.getAttribute("width"))))
+                # Is there anyone at that RowColumn?
+                someoneIsThereAlready = False
+                for existingColumns in highestRow.getElementsByTagName("Column"):
+                    if existingColumns.getAttribute("columnId") >= widestColumn:
+                        someoneIsThereAlready = True
+                if not someoneIsThereAlready :
+                    highestRow.appendChild(gridladder.createElement("Column"))
+                    highestRow.lastChild.setAttribute("columnId",widestColumn)
+                    highestRow.lastChild.setAttribute("localId",elly.getAttribute("localId"))
+                    highestRow.lastChild.setAttribute("width","1")
+                # TODO Do something else if someone is already there
+                # TODO You will have to flag that it is parallel
+
+        #rightPowerRail (think CODESYS were having a laugh)
+    # How wide to make network? well:
+    # 1. contacts and coils = 1
+    # 2. blocks and executes = 3
+    # 3. branches themselves don't take up additional room
+    # 4. but... you have to work out the longest path on each branch
+    # Data is presented localId + refLocalId [+ refLocalId + ...]
+    # So I guess it is easiest to work our way backwards.  (from right to left)
+    # We will naïvely look at every localId and how long it takes to get back to refLocalId=0
+    # We also naïvely look at every possible localId, even if we've already found him
+    # We've actually already calculated that above, yay for me!
+    print(widthOfLadder)
+  
+    # Array of networks
+    # Network is an array of Contact / Block / Coil
+    # So we know it is (widthOfLadder) wide... so we could have an array.. no that's not right
+    # 1. Pass through every element
+    # 2. hmm, lets make a new ladder xml, which is the rows... input variables and labels can be added last
+    # 3. <Row>
+    #       <Column columnId="0" refLocalId=(localID of vendorElement new network) />
+    #       <Column columnId="1" refLocalId=(localID of next contact/block/coil) />
+    # 4. The next element comes in. It asks if anybody already has the row right behind its refLocalId
+    #     If someone is already there, it starts a new Row, starting at the columnId just behind
+    # 5. If it has two refLocalIds, it tries to get the furthest back column
+    print (str(gridladder.toprettyxml()))
+  
+    # should now have a declaration section
+    # a bunch of inputs
+    # a bunch of outputs
+    # and a bunch of blocks
+    # convert them all to a nice easy format
+    print ("{Declaration}")
+    print (declarationheader)
+    print ("{/Declaration}")
+else:
+    print("Maybe I want one argument, whch is the PLCOPEN XML.")
+    print("Will output to current directory as Ladder0.ladder")
+