This is an automated email from the ASF dual-hosted git repository.

sruehl pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit e57521cd5cd66a0e5c34de3eb423f0bc05050cb0
Author: Sebastian Rühl <[email protected]>
AuthorDate: Mon Apr 19 14:53:26 2021 +0200

    plc4go: implemented a simple XmlBasedWriter
---
 plc4go/internal/plc4go/s7/s7Io_test.go             |  69 ++++++-
 .../plc4go/spi/utils/WriteBufferByteBased.go       |   4 +-
 .../plc4go/spi/utils/WriteBufferXmlBased.go        | 204 +++++++++++++++++++++
 3 files changed, 273 insertions(+), 4 deletions(-)

diff --git a/plc4go/internal/plc4go/s7/s7Io_test.go 
b/plc4go/internal/plc4go/s7/s7Io_test.go
index 5dd413d..6577994 100644
--- a/plc4go/internal/plc4go/s7/s7Io_test.go
+++ b/plc4go/internal/plc4go/s7/s7Io_test.go
@@ -42,6 +42,7 @@ func TestS7MessageBytes(t *testing.T) {
                args                 args
                wantString           string
                wantStringSerialized string
+               wantStringXml        string
                wantDump             string
        }{
                {
@@ -150,6 +151,63 @@ func TestS7MessageBytes(t *testing.T) {
 
║╚══════════════════════════════════════════════════════════════════════════════════════════════════════════════╝║
 
╚════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝
 `,
+                       wantStringXml: `
+<TPKTPacket>
+  <protocolId dataType="uint8" bitLength="8">3</protocolId>
+  <reserved dataType="uint8" bitLength="8">0</reserved>
+  <len dataType="uint16" bitLength="16">29</len>
+  <COTPPacket>
+    <headerLength dataType="uint8" bitLength="8">5</headerLength>
+    <tpduCode dataType="uint8" bitLength="8">240</tpduCode>
+    <COTPPacketData>
+      <eot dataType="bit" bitLength="1">false</eot>
+      <tpduRef dataType="uint8" bitLength="7">13</tpduRef>
+    </COTPPacketData>
+    <parameters>
+      <COTPParameter>
+        <parameterType dataType="uint8" bitLength="8">192</parameterType>
+        <parameterLength dataType="uint8" bitLength="8">1</parameterLength>
+        <COTPParameterTpduSize>
+          <COTPTpduSize dataType="int8" bitLength="8" 
stringRepresentation="SIZE_4096">12</COTPTpduSize>
+        </COTPParameterTpduSize>
+      </COTPParameter>
+    </parameters>
+    <S7Message>
+      <protocolId dataType="uint8" bitLength="8">50</protocolId>
+      <messageType dataType="uint8" bitLength="8">3</messageType>
+      <reserved dataType="uint16" bitLength="16">0</reserved>
+      <tpduReference dataType="uint16" bitLength="16">11</tpduReference>
+      <parameterLength dataType="uint16" bitLength="16">2</parameterLength>
+      <payloadLength dataType="uint16" bitLength="16">5</payloadLength>
+      <S7MessageResponseData>
+        <errorClass dataType="uint8" bitLength="8">0</errorClass>
+        <errorCode dataType="uint8" bitLength="8">0</errorCode>
+      </S7MessageResponseData>
+      <S7Parameter>
+        <parameterType dataType="uint8" bitLength="8">4</parameterType>
+        <S7ParameterReadVarResponse>
+          <numItems dataType="uint8" bitLength="8">4</numItems>
+        </S7ParameterReadVarResponse>
+      </S7Parameter>
+      <S7Payload>
+        <S7PayloadReadVarResponse>
+          <items>
+            <S7VarPayloadDataItem>
+              <DataTransportErrorCode dataType="uint8" bitLength="8" 
stringRepresentation="OK">255</DataTransportErrorCode>
+              <DataTransportSize dataType="uint8" bitLength="8" 
stringRepresentation="BIT">3</DataTransportSize>
+              <dataLength dataType="uint16" bitLength="16">1</dataLength>
+              <data>
+                <value dataType="int8" bitLength="8">1</value>
+              </data>
+              <padding></padding>
+            </S7VarPayloadDataItem>
+          </items>
+        </S7PayloadReadVarResponse>
+      </S7Payload>
+    </S7Message>
+  </COTPPacket>
+</TPKTPacket>
+`,
                        wantDump: `
 00|03 00 00 1d 05 f0 0d c0 01 0c '..........'
 10|32 03 00 00 00 0b 00 02 00 05 '2.........'
@@ -171,9 +229,16 @@ func TestS7MessageBytes(t *testing.T) {
                        if got := string(boxWriter.GetBox()); got != 
tt.wantStringSerialized {
                                t.Errorf("Serialize() = '\n%v\n', want 
'\n%v\n'", got, tt.wantStringSerialized)
                        }
+                       xmlWriteBuffer := utils.NewXmlWriteBuffer()
+                       if err := tt.args.debuggable.Serialize(xmlWriteBuffer); 
err != nil {
+                               t.Error(err)
+                       }
+                       tt.wantStringXml = strings.Trim(tt.wantStringXml, "\n")
+                       if got := xmlWriteBuffer.GetXmlString(); got != 
tt.wantStringXml {
+                               t.Errorf("Serialize() = '\n%v\n', want 
'\n%v\n'", got, tt.wantStringXml)
+                       }
                        buffer := utils.NewWriteBuffer()
-                       err := tt.args.debuggable.Serialize(buffer)
-                       if err != nil {
+                       if err := tt.args.debuggable.Serialize(buffer); err != 
nil {
                                t.Error(err)
                        }
                        tt.wantDump = strings.Trim(tt.wantDump, "\n")
diff --git a/plc4go/internal/plc4go/spi/utils/WriteBufferByteBased.go 
b/plc4go/internal/plc4go/spi/utils/WriteBufferByteBased.go
index 6654938..b10f09f 100644
--- a/plc4go/internal/plc4go/spi/utils/WriteBufferByteBased.go
+++ b/plc4go/internal/plc4go/spi/utils/WriteBufferByteBased.go
@@ -73,11 +73,11 @@ type writeBuffer struct {
 ///////////////////////////////////////
 ///////////////////////////////////////
 
-func (rb *writeBuffer) PushContext(_ string, writerArgs ...WithWriterArgs) 
error {
+func (rb *writeBuffer) PushContext(_ string, _ ...WithWriterArgs) error {
        return nil
 }
 
-func (rb *writeBuffer) PopContext(_ string, writerArgs ...WithWriterArgs) 
error {
+func (rb *writeBuffer) PopContext(_ string, _ ...WithWriterArgs) error {
        return nil
 }
 
diff --git a/plc4go/internal/plc4go/spi/utils/WriteBufferXmlBased.go 
b/plc4go/internal/plc4go/spi/utils/WriteBufferXmlBased.go
new file mode 100644
index 0000000..a52fb3d
--- /dev/null
+++ b/plc4go/internal/plc4go/spi/utils/WriteBufferXmlBased.go
@@ -0,0 +1,204 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+package utils
+
+import (
+       "bufio"
+       "encoding/xml"
+       "fmt"
+       "math/big"
+       "strings"
+)
+
+type WriteBufferXmlBased interface {
+       WriteBuffer
+       GetXmlString() string
+}
+
+func NewXmlWriteBuffer() WriteBufferXmlBased {
+       var xmlString strings.Builder
+       encoder := xml.NewEncoder(bufio.NewWriterSize(&xmlString, 1024*16))
+       encoder.Indent("", "  ")
+       return &xmlWriteBuffer{
+               xmlString: &xmlString,
+               Encoder:   encoder,
+       }
+}
+
+///////////////////////////////////////
+///////////////////////////////////////
+//
+// Internal section
+//
+
+type xmlWriteBuffer struct {
+       xmlString *strings.Builder
+       *xml.Encoder
+}
+
+//
+// Internal section
+//
+///////////////////////////////////////
+///////////////////////////////////////
+
+func (x *xmlWriteBuffer) PushContext(logicalName string, _ ...WithWriterArgs) 
error {
+       // Pre-emptive flush to avoid overflow when for a long time no context 
gets popped
+       if err := x.Encoder.Flush(); err != nil {
+               return err
+       }
+       return x.Encoder.EncodeToken(xml.StartElement{Name: xml.Name{Local: 
sanitizeLogicalName(logicalName)}})
+}
+
+func (x *xmlWriteBuffer) WriteBit(logicalName string, value bool, writerArgs 
...WithWriterArgs) error {
+       return x.EncodeElement(value, xml.StartElement{
+               Name: xml.Name{Local: sanitizeLogicalName(logicalName)},
+               Attr: generateAttr("bit", 1, writerArgs...),
+       })
+}
+
+func (x *xmlWriteBuffer) WriteUint8(logicalName string, bitLength uint8, value 
uint8, writerArgs ...WithWriterArgs) error {
+       return x.EncodeElement(value, xml.StartElement{
+               Name: xml.Name{Local: sanitizeLogicalName(logicalName)},
+               Attr: generateAttr("uint8", bitLength, writerArgs...),
+       })
+}
+
+func (x *xmlWriteBuffer) WriteUint16(logicalName string, bitLength uint8, 
value uint16, writerArgs ...WithWriterArgs) error {
+       return x.EncodeElement(value, xml.StartElement{
+               Name: xml.Name{Local: sanitizeLogicalName(logicalName)},
+               Attr: generateAttr("uint16", bitLength, writerArgs...),
+       })
+}
+
+func (x *xmlWriteBuffer) WriteUint32(logicalName string, bitLength uint8, 
value uint32, writerArgs ...WithWriterArgs) error {
+       return x.EncodeElement(value, xml.StartElement{
+               Name: xml.Name{Local: sanitizeLogicalName(logicalName)},
+               Attr: generateAttr("uint32", bitLength, writerArgs...),
+       })
+}
+
+func (x *xmlWriteBuffer) WriteUint64(logicalName string, bitLength uint8, 
value uint64, writerArgs ...WithWriterArgs) error {
+       return x.EncodeElement(value, xml.StartElement{
+               Name: xml.Name{Local: sanitizeLogicalName(logicalName)},
+               Attr: generateAttr("uint64", bitLength, writerArgs...),
+       })
+}
+
+func (x *xmlWriteBuffer) WriteInt8(logicalName string, bitLength uint8, value 
int8, writerArgs ...WithWriterArgs) error {
+       return x.EncodeElement(value, xml.StartElement{
+               Name: xml.Name{Local: sanitizeLogicalName(logicalName)},
+               Attr: generateAttr("int8", bitLength, writerArgs...),
+       })
+}
+
+func (x *xmlWriteBuffer) WriteInt16(logicalName string, bitLength uint8, value 
int16, writerArgs ...WithWriterArgs) error {
+       return x.EncodeElement(value, xml.StartElement{
+               Name: xml.Name{Local: sanitizeLogicalName(logicalName)},
+               Attr: generateAttr("int16", bitLength, writerArgs...),
+       })
+}
+
+func (x *xmlWriteBuffer) WriteInt32(logicalName string, bitLength uint8, value 
int32, writerArgs ...WithWriterArgs) error {
+       return x.EncodeElement(value, xml.StartElement{
+               Name: xml.Name{Local: sanitizeLogicalName(logicalName)},
+               Attr: generateAttr("int32", bitLength, writerArgs...),
+       })
+}
+
+func (x *xmlWriteBuffer) WriteInt64(logicalName string, bitLength uint8, value 
int64, writerArgs ...WithWriterArgs) error {
+       return x.EncodeElement(value, xml.StartElement{
+               Name: xml.Name{Local: sanitizeLogicalName(logicalName)},
+               Attr: generateAttr("int64", bitLength, writerArgs...),
+       })
+}
+
+func (x *xmlWriteBuffer) WriteBigInt(logicalName string, bitLength uint8, 
value *big.Int, writerArgs ...WithWriterArgs) error {
+       return x.EncodeElement(value, xml.StartElement{
+               Name: xml.Name{Local: sanitizeLogicalName(logicalName)},
+               Attr: generateAttr("bigInt", bitLength, writerArgs...),
+       })
+}
+
+func (x *xmlWriteBuffer) WriteFloat32(logicalName string, bitLength uint8, 
value float32, writerArgs ...WithWriterArgs) error {
+       return x.EncodeElement(value, xml.StartElement{
+               Name: xml.Name{Local: sanitizeLogicalName(logicalName)},
+               Attr: generateAttr("float32", bitLength, writerArgs...),
+       })
+}
+
+func (x *xmlWriteBuffer) WriteFloat64(logicalName string, bitLength uint8, 
value float64, writerArgs ...WithWriterArgs) error {
+       return x.EncodeElement(value, xml.StartElement{
+               Name: xml.Name{Local: sanitizeLogicalName(logicalName)},
+               Attr: generateAttr("float64", bitLength, writerArgs...),
+       })
+}
+
+func (x *xmlWriteBuffer) WriteString(logicalName string, bitLength uint8, 
encoding string, value string, writerArgs ...WithWriterArgs) error {
+       attr := generateAttr("string", bitLength, writerArgs...)
+       attr = append(attr, xml.Attr{Name: xml.Name{Local: "encoding"}, Value: 
encoding})
+       return x.EncodeElement(value, xml.StartElement{
+               Name: xml.Name{Local: sanitizeLogicalName(logicalName)},
+               Attr: attr,
+       })
+}
+
+func (x *xmlWriteBuffer) PopContext(logicalName string, _ ...WithWriterArgs) 
error {
+       if err := x.Encoder.EncodeToken(xml.EndElement{Name: xml.Name{Local: 
sanitizeLogicalName(logicalName)}}); err != nil {
+               return err
+       }
+       return x.Encoder.Flush()
+}
+
+func (x *xmlWriteBuffer) GetXmlString() string {
+       return x.xmlString.String()
+}
+
+func generateAttr(dataType string, bitLength uint8, writerArgs 
...WithWriterArgs) []xml.Attr {
+       attrs := make([]xml.Attr, 2)
+       attrs[0] = xml.Attr{
+               Name:  xml.Name{Local: "dataType"},
+               Value: dataType,
+       }
+       attrs[1] = xml.Attr{
+               Name:  xml.Name{Local: "bitLength"},
+               Value: fmt.Sprintf("%d", bitLength),
+       }
+       for _, arg := range writerArgs {
+               if !arg.isWriterArgs() {
+                       panic("not a writer arg")
+               }
+               switch arg.(type) {
+               case withAdditionalStringRepresentation:
+                       attrs = append(attrs, xml.Attr{
+                               Name:  xml.Name{Local: "stringRepresentation"},
+                               Value: 
arg.(withAdditionalStringRepresentation).stringRepresentation,
+                       })
+               }
+       }
+       return attrs
+}
+
+func sanitizeLogicalName(logicalName string) string {
+       if logicalName == "" {
+               return "value"
+       }
+       return logicalName
+}

Reply via email to