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 e7f2f4c6b11725522dfe9326fe3ec00500d7cb34
Author: Sebastian Rühl <[email protected]>
AuthorDate: Tue Apr 20 16:08:58 2021 +0200

    plc4j: simple xml based reader
---
 .../resources/templates/java/io-template.java.ftlh |   3 +-
 plc4j/drivers/s7/src/test/java/S7IoTest.java       | 134 +++++++++++
 plc4j/drivers/s7/src/test/java/s7IoTest.java       | 121 ----------
 .../java/spi/generation/ReadBufferXmlBased.java    | 264 +++++++++++++++++++++
 .../java/spi/generation/WriteBufferXmlBased.java   | 125 ++++------
 5 files changed, 449 insertions(+), 198 deletions(-)

diff --git 
a/build-utils/language-java/src/main/resources/templates/java/io-template.java.ftlh
 
b/build-utils/language-java/src/main/resources/templates/java/io-template.java.ftlh
index 7c10357..bf7c604 100644
--- 
a/build-utils/language-java/src/main/resources/templates/java/io-template.java.ftlh
+++ 
b/build-utils/language-java/src/main/resources/templates/java/io-template.java.ftlh
@@ -218,8 +218,8 @@ public class ${type.name}IO implements <#if outputFlavor != 
"passive">MessageIO<
         ${helper.getLanguageTypeNameForField(field)}[] ${arrayField.name} = 
_${arrayField.name}List.toArray(new 
${helper.getNonPrimitiveLanguageTypeNameForField(arrayField)}[0]);
             </#if>
         </#if>
-        <#break>
         io.closeContext("${arrayField.name}");
+        <#break>
     <#case "checksum">
         <#assign checksumField = field>
         <#assign simpleTypeReference = checksumField.type>
@@ -424,6 +424,7 @@ public class ${type.name}IO implements <#if outputFlavor != 
"passive">MessageIO<
 </#switch>
 </#list>
 
+        io.closeContext("${type.name}");
         // Create the instance
         <#if helper.isDiscriminatedChildTypeDefinition()>
         return new ${type.name}Builder(<#list type.propertyFields as 
field>${field.name}<#sep>, </#sep></#list>);
diff --git a/plc4j/drivers/s7/src/test/java/S7IoTest.java 
b/plc4j/drivers/s7/src/test/java/S7IoTest.java
new file mode 100644
index 0000000..a96e27c
--- /dev/null
+++ b/plc4j/drivers/s7/src/test/java/S7IoTest.java
@@ -0,0 +1,134 @@
+/*
+ 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.
+ */
+
+import org.apache.plc4x.java.s7.readwrite.*;
+import org.apache.plc4x.java.s7.readwrite.io.TPKTPacketIO;
+import org.apache.plc4x.java.s7.readwrite.types.COTPTpduSize;
+import org.apache.plc4x.java.s7.readwrite.types.DataTransportErrorCode;
+import org.apache.plc4x.java.s7.readwrite.types.DataTransportSize;
+import org.apache.plc4x.java.spi.generation.ReadBufferXmlBased;
+import org.apache.plc4x.java.spi.generation.WriteBufferXmlBased;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+
+import java.io.ByteArrayInputStream;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class S7IoTest {
+
+    // TODO: delete when xml is good
+    boolean doneDesigningJavaXml = false;
+
+    @Disabled("Till the output is aligned to the one of golang")
+    @Test
+    void TestS7MessageBytes() throws Exception {
+        String wantXml =
+            "<TPKTPacket>\n" +
+                "    <protocolId bitLength=\"8\" 
dataType=\"uint8\">3</protocolId>\n" +
+                "    <reserved bitLength=\"8\" 
dataType=\"uint8\">0</reserved>\n" +
+                "    <len bitLength=\"16\" dataType=\"uint16\">29</len>\n" +
+                "    <COTPPacket>\n" +
+                "        <headerLength bitLength=\"8\" 
dataType=\"uint18\">5</headerLength>\n" +
+                "        <tpduCode bitLength=\"8\" 
dataType=\"uint8\">240</tpduCode>\n" +
+                "        <COTPPacketData>\n" +
+                "            <eot bitLength=\"1\" 
dataType=\"bit\">false</eot>\n" +
+                "            <tpduRef bitLength=\"7\" 
dataType=\"uint8\">13</tpduRef>\n" +
+                "        </COTPPacketData>\n" +
+                "        <parameters>\n" +
+                "            <COTPParameter>\n" +
+                "                <parameterType bitLength=\"8\" 
dataType=\"uint8\">192</parameterType>\n" +
+                "                <parameterLength bitLength=\"8\" 
dataType=\"uint8\">1</parameterLength>\n" +
+                "                <COTPParameterTpduSize>\n" +
+                "                    <COTPTpduSize bitLength=\"8\" 
dataType=\"uint8\" stringRepresentation=\"SIZE_4096\">12</COTPTpduSize>\n" +
+                "                </COTPParameterTpduSize>\n" +
+                "            </COTPParameter>\n" +
+                "        </parameters>\n" +
+                "        <S7Message>\n" +
+                "            <protocolId bitLength=\"8\" 
dataType=\"uint8\">50</protocolId>\n" +
+                "            <messageType bitLength=\"8\" 
dataType=\"uint8\">3</messageType>\n" +
+                "            <reserved bitLength=\"16\" 
dataType=\"uint16\">0</reserved>\n" +
+                "            <tpduReference bitLength=\"16\" 
dataType=\"uint16\">11</tpduReference>\n" +
+                "            <parameterLength bitLength=\"16\" 
dataType=\"uint16\">2</parameterLength>\n" +
+                "            <payloadLength bitLength=\"16\" 
dataType=\"uint16\">5</payloadLength>\n" +
+                "            <S7MessageResponseData>\n" +
+                "                <errorClass bitLength=\"8\" 
dataType=\"uint8\">0</errorClass>\n" +
+                "                <errorCode bitLength=\"8\" 
dataType=\"uint8\">0</errorCode>\n" +
+                "            </S7MessageResponseData>\n" +
+                "            <S7Parameter>\n" +
+                "                <parameterType bitLength=\"8\" 
dataType=\"uint8\">4</parameterType>\n" +
+                "                <S7ParameterReadVarResponse>\n" +
+                "                    <numItems bitLength=\"8\" 
dataType=\"uint8\">1</numItems>\n" +
+                "                </S7ParameterReadVarResponse>\n" +
+                "            </S7Parameter>\n" +
+                "            <S7Payload>\n" +
+                "                <S7PayloadReadVarResponse>\n" +
+                "                    <items>\n" +
+                "                        <S7VarPayloadDataItem>\n" +
+                "                            <DataTransportErrorCode 
bitLength=\"8\" dataType=\"uint8\" 
stringRepresentation=\"OK\">255</DataTransportErrorCode>\n" +
+                "                            <DataTransportSize 
bitLength=\"8\" dataType=\"uint8\" 
stringRepresentation=\"BIT\">3</DataTransportSize>\n" +
+                "                            <dataLength bitLength=\"16\" 
dataType=\"uint16\">1</dataLength>\n" +
+                "                            <data>\n" +
+                "                                <value bitLength=\"8\" 
dataType=\"int8\">1</value>\n" +
+                "                            </data>\n" +
+                "                            <padding></padding>\n" +
+                "                        </S7VarPayloadDataItem>\n" +
+                "                    </items>\n" +
+                "                </S7PayloadReadVarResponse>\n" +
+                "            </S7Payload>\n" +
+                "        </S7Message>\n" +
+                "    </COTPPacket>\n" +
+                "</TPKTPacket>\n";
+
+
+        TPKTPacket tpktPacket = new TPKTPacket(
+            new COTPPacketData(
+                new COTPParameter[]{new 
COTPParameterTpduSize(COTPTpduSize.SIZE_4096)},
+                new S7MessageResponseData(
+                    11,
+                    new S7ParameterReadVarResponse((short) 1),
+                    new S7PayloadReadVarResponse(
+                        new S7VarPayloadDataItem[]{
+                            new S7VarPayloadDataItem(
+                                DataTransportErrorCode.OK,
+                                DataTransportSize.BIT,
+                                new byte[]{0x1}
+                            )
+                        }
+                    ),
+                    (short) 0,
+                    (short) 0
+                ),
+                false,
+                (short) 13
+            )
+        );
+        WriteBufferXmlBased writeBufferXmlBased = new WriteBufferXmlBased();
+        TPKTPacketIO.staticSerialize(writeBufferXmlBased, tpktPacket);
+        String gotXml = writeBufferXmlBased.getXmlString();
+        if (doneDesigningJavaXml) {
+            assertEquals(wantXml, gotXml);
+        }
+        System.out.println(gotXml);
+        ReadBufferXmlBased readBufferXmlBased = new ReadBufferXmlBased(new 
ByteArrayInputStream(gotXml.getBytes()));
+        TPKTPacket reReadTpktPacket = 
TPKTPacketIO.staticParse(readBufferXmlBased);
+        
assertThat(reReadTpktPacket).usingRecursiveComparison().isEqualTo(tpktPacket);
+    }
+}
diff --git a/plc4j/drivers/s7/src/test/java/s7IoTest.java 
b/plc4j/drivers/s7/src/test/java/s7IoTest.java
deleted file mode 100644
index 977cb9b..0000000
--- a/plc4j/drivers/s7/src/test/java/s7IoTest.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- 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.
- */
-
-import org.apache.plc4x.java.s7.readwrite.*;
-import org.apache.plc4x.java.s7.readwrite.io.TPKTPacketIO;
-import org.apache.plc4x.java.s7.readwrite.types.COTPTpduSize;
-import org.apache.plc4x.java.s7.readwrite.types.DataTransportErrorCode;
-import org.apache.plc4x.java.s7.readwrite.types.DataTransportSize;
-import org.apache.plc4x.java.spi.generation.WriteBufferXmlBased;
-import org.junit.jupiter.api.Disabled;
-import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-public class s7IoTest {
-
-    @Disabled("Till the output is aligned to the one of golang")
-    @Test
-    void TestS7MessageBytes() throws Exception {
-        String wantXml =
-            "<TPKTPacket>\n" +
-            "    <protocolId bitLength=\"8\" 
dataType=\"uint8\">3</protocolId>\n" +
-            "    <reserved bitLength=\"8\" dataType=\"uint8\">0</reserved>\n" +
-            "    <len bitLength=\"16\" dataType=\"uint16\">29</len>\n" +
-            "    <COTPPacket>\n" +
-            "        <headerLength bitLength=\"8\" 
dataType=\"uint18\">5</headerLength>\n" +
-            "        <tpduCode bitLength=\"8\" 
dataType=\"uint8\">240</tpduCode>\n" +
-            "        <COTPPacketData>\n" +
-            "            <eot bitLength=\"1\" dataType=\"bit\">false</eot>\n" +
-            "            <tpduRef bitLength=\"7\" 
dataType=\"uint8\">13</tpduRef>\n" +
-            "        </COTPPacketData>\n" +
-            "        <parameters>\n" +
-            "            <COTPParameter>\n" +
-            "                <parameterType bitLength=\"8\" 
dataType=\"uint8\">192</parameterType>\n" +
-            "                <parameterLength bitLength=\"8\" 
dataType=\"uint8\">1</parameterLength>\n" +
-            "                <COTPParameterTpduSize>\n" +
-            "                    <COTPTpduSize bitLength=\"8\" 
dataType=\"uint8\" stringRepresentation=\"SIZE_4096\">12</COTPTpduSize>\n" +
-            "                </COTPParameterTpduSize>\n" +
-            "            </COTPParameter>\n" +
-            "        </parameters>\n" +
-            "        <S7Message>\n" +
-            "            <protocolId bitLength=\"8\" 
dataType=\"uint8\">50</protocolId>\n" +
-            "            <messageType bitLength=\"8\" 
dataType=\"uint8\">3</messageType>\n" +
-            "            <reserved bitLength=\"16\" 
dataType=\"uint16\">0</reserved>\n" +
-            "            <tpduReference bitLength=\"16\" 
dataType=\"uint16\">11</tpduReference>\n" +
-            "            <parameterLength bitLength=\"16\" 
dataType=\"uint16\">2</parameterLength>\n" +
-            "            <payloadLength bitLength=\"16\" 
dataType=\"uint16\">5</payloadLength>\n" +
-            "            <S7MessageResponseData>\n" +
-            "                <errorClass bitLength=\"8\" 
dataType=\"uint8\">0</errorClass>\n" +
-            "                <errorCode bitLength=\"8\" 
dataType=\"uint8\">0</errorCode>\n" +
-            "            </S7MessageResponseData>\n" +
-            "            <S7Parameter>\n" +
-            "                <parameterType bitLength=\"8\" 
dataType=\"uint8\">4</parameterType>\n" +
-            "                <S7ParameterReadVarResponse>\n" +
-            "                    <numItems bitLength=\"8\" 
dataType=\"uint8\">1</numItems>\n" +
-            "                </S7ParameterReadVarResponse>\n" +
-            "            </S7Parameter>\n" +
-            "            <S7Payload>\n" +
-            "                <S7PayloadReadVarResponse>\n" +
-            "                    <items>\n" +
-            "                        <S7VarPayloadDataItem>\n" +
-            "                            <DataTransportErrorCode 
bitLength=\"8\" dataType=\"uint8\" 
stringRepresentation=\"OK\">255</DataTransportErrorCode>\n" +
-            "                            <DataTransportSize bitLength=\"8\" 
dataType=\"uint8\" stringRepresentation=\"BIT\">3</DataTransportSize>\n" +
-            "                            <dataLength bitLength=\"16\" 
dataType=\"uint16\">1</dataLength>\n" +
-            "                            <data>\n" +
-            "                                <value bitLength=\"8\" 
dataType=\"int8\">1</value>\n" +
-            "                            </data>\n" +
-            "                            <padding></padding>\n" +
-            "                        </S7VarPayloadDataItem>\n" +
-            "                    </items>\n" +
-            "                </S7PayloadReadVarResponse>\n" +
-            "            </S7Payload>\n" +
-            "        </S7Message>\n" +
-            "    </COTPPacket>\n" +
-            "</TPKTPacket>";
-
-
-        TPKTPacket tpktPacket = new TPKTPacket(
-            new COTPPacketData(
-                new COTPParameter[]{new 
COTPParameterTpduSize(COTPTpduSize.SIZE_4096)},
-                new S7MessageResponseData(
-                    11,
-                    new S7ParameterReadVarResponse((short) 1),
-                    new S7PayloadReadVarResponse(
-                        new S7VarPayloadDataItem[]{
-                            new S7VarPayloadDataItem(
-                                DataTransportErrorCode.OK,
-                                DataTransportSize.BIT,
-                                new byte[]{0x1}
-                            )
-                        }
-                    ),
-                    (short) 0,
-                    (short) 0
-                ),
-                false,
-                (short) 13
-            )
-        );
-        WriteBufferXmlBased writeBufferXmlBased = new WriteBufferXmlBased();
-        TPKTPacketIO.staticSerialize(writeBufferXmlBased, tpktPacket);
-        String gotXml = writeBufferXmlBased.getXmlString();
-        assertEquals(wantXml,gotXml);
-    }
-}
diff --git 
a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferXmlBased.java
 
b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferXmlBased.java
new file mode 100644
index 0000000..ec777b0
--- /dev/null
+++ 
b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/ReadBufferXmlBased.java
@@ -0,0 +1,264 @@
+/*
+ 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 org.apache.plc4x.java.spi.generation;
+
+import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.*;
+import java.io.InputStream;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Iterator;
+
+public class ReadBufferXmlBased implements ReadBuffer {
+
+    XMLEventReader reader;
+
+    int pos = 1;
+
+    public ReadBufferXmlBased(InputStream is) {
+        XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
+        try {
+            reader = xmlInputFactory.createXMLEventReader(is);
+        } catch (XMLStreamException e) {
+            throw new PlcRuntimeException(e);
+        }
+    }
+
+    @Override
+    public int getPos() {
+        return pos / 8;
+    }
+
+    @Override
+    public boolean hasMore(int numBits) {
+        return true;
+    }
+
+    @Override
+    public void pullContext(String logicalName) {
+        StartElement startElement = travelToNextStartElement();
+        String elementName = startElement.getName().getLocalPart();
+        if (!elementName.equals(logicalName)) {
+            throw new PlcRuntimeException(String.format("Unexpected Start 
element '%s'. Expected '%s'", elementName, logicalName));
+        }
+    }
+
+    @Override
+    public boolean readBit(String logicalName) throws ParseException {
+        String bit = decode(logicalName, "bit", 1);
+        move(1);
+        return bit.equals("1");
+    }
+
+    @Override
+    public byte readUnsignedByte(String logicalName, int bitLength) throws 
ParseException {
+        move(bitLength);
+        return Byte.parseByte(decode(logicalName, "uint8", bitLength));
+    }
+
+    @Override
+    public short readUnsignedShort(String logicalName, int bitLength) throws 
ParseException {
+        move(bitLength);
+        return Short.parseShort(decode(logicalName, "uint16", bitLength));
+    }
+
+    @Override
+    public int readUnsignedInt(String logicalName, int bitLength) throws 
ParseException {
+        move(bitLength);
+        return Integer.parseInt(decode(logicalName, "uint32", bitLength));
+    }
+
+    @Override
+    public long readUnsignedLong(String logicalName, int bitLength) throws 
ParseException {
+        move(bitLength);
+        return Long.parseLong(decode(logicalName, "uint32", bitLength));
+    }
+
+    @Override
+    public BigInteger readUnsignedBigInteger(String logicalName, int 
bitLength) throws ParseException {
+        move(bitLength);
+        throw new PlcRuntimeException("not implemented yet");
+    }
+
+    @Override
+    public byte readByte(String logicalName, int bitLength) throws 
ParseException {
+        move(bitLength);
+        return Byte.parseByte(decode(logicalName, "int8", bitLength));
+    }
+
+    @Override
+    public short readShort(String logicalName, int bitLength) throws 
ParseException {
+        move(bitLength);
+        return Short.parseShort(decode(logicalName, "int16", bitLength));
+    }
+
+    @Override
+    public int readInt(String logicalName, int bitLength) throws 
ParseException {
+        move(bitLength);
+        return Integer.parseInt(decode(logicalName, "int32", bitLength));
+    }
+
+    @Override
+    public long readLong(String logicalName, int bitLength) throws 
ParseException {
+        move(bitLength);
+        return Long.parseLong(decode(logicalName, "int64", bitLength));
+    }
+
+    @Override
+    public BigInteger readBigInteger(String logicalName, int bitLength) throws 
ParseException {
+        move(bitLength);
+        throw new PlcRuntimeException("not implemented yet");
+    }
+
+    @Override
+    public float readFloat(String logicalName, int bitLength) throws 
ParseException {
+        move(bitLength);
+        return Float.parseFloat(decode(logicalName, "float32", bitLength));
+    }
+
+    @Override
+    public double readDouble(String logicalName, int bitLength) throws 
ParseException {
+        move(bitLength);
+        return Double.parseDouble(decode(logicalName, "float64", bitLength));
+    }
+
+    @Override
+    public BigDecimal readBigDecimal(String logicalName, int bitLength) throws 
ParseException {
+        move(bitLength);
+        throw new PlcRuntimeException("not implemented yet");
+    }
+
+    @Override
+    public String readString(String logicalName, int bitLength, String 
encoding) {
+        move(bitLength);
+        return decode(logicalName, "string", bitLength);
+    }
+
+    @Override
+    public void closeContext(String logicalName) {
+        EndElement endElement = travelToNextEndElement();
+        if (!endElement.getName().getLocalPart().equals(logicalName)) {
+            throw new PlcRuntimeException(String.format("Unexpected End 
element '%s'. Expected '%s'", endElement.getName().getLocalPart(), 
logicalName));
+        }
+    }
+
+    private void move(int bits) {
+        pos += bits;
+    }
+
+    private StartElement travelToNextStartElement() {
+        while (reader.hasNext()) {
+            XMLEvent xmlEvent;
+            try {
+                xmlEvent = reader.nextEvent();
+            } catch (XMLStreamException e) {
+                throw new PlcRuntimeException(e);
+            }
+            if (xmlEvent.isStartElement()) {
+                return xmlEvent.asStartElement();
+            } else if (xmlEvent.isEndElement()) {
+                throw new PlcRuntimeException(String.format("Unexpected End 
element %s", xmlEvent.asEndElement().getName().getLocalPart()));
+            }
+        }
+        throw new PlcRuntimeException("EOF");
+    }
+
+    private EndElement travelToNextEndElement() {
+        while (reader.hasNext()) {
+            XMLEvent xmlEvent;
+            try {
+                xmlEvent = reader.nextEvent();
+            } catch (XMLStreamException e) {
+                throw new PlcRuntimeException(e);
+            }
+            if (xmlEvent.isStartElement()) {
+                throw new PlcRuntimeException("Unexpected Start element" + 
xmlEvent.asEndElement().getName().getLocalPart());
+            } else if (xmlEvent.isEndElement()) {
+                return xmlEvent.asEndElement();
+            }
+        }
+        throw new PlcRuntimeException("EOF");
+    }
+
+    private String decode(String logicalName, String dataType, int bitLength) {
+        StartElement startElement = travelToNextStartElement();
+        validateStartElement(startElement, logicalName, dataType, bitLength);
+        Characters characters = null;
+        try {
+            characters = reader.nextEvent().asCharacters();
+        } catch (XMLStreamException e) {
+            throw new PlcRuntimeException(e);
+        }
+        String data = characters.getData();
+        try {
+            XMLEvent endEvent = reader.nextEvent().asEndElement();
+        } catch (XMLStreamException e) {
+            throw new PlcRuntimeException(e);
+        }
+        return data;
+    }
+
+    private boolean validateStartElement(StartElement startElement, String 
logicalName, String dataType, int bitLength) {
+        logicalName = sanitizeLogicalName(logicalName);
+        if (!startElement.getName().getLocalPart().equals(logicalName)) {
+            throw new PlcRuntimeException(String.format("unexpected element 
'%s'. Expected '%s'", startElement.getName().getLocalPart(), logicalName));
+        } else if (!validateAttr(startElement.getAttributes(), dataType, 
bitLength)) {
+            throw new PlcRuntimeException("Error validating Attributes");
+        }
+        return true;
+    }
+
+    private boolean validateAttr(Iterator<Attribute> attr, String dataType, 
int bitLength) {
+        boolean dataTypeValidated = false;
+        boolean bitLengthValidate = false;
+        while (attr.hasNext()) {
+            Attribute attribute = attr.next();
+            if (attribute.getName().getLocalPart().equals("dataType")) {
+                if (!attribute.getValue().equals(dataType)) {
+                    throw new PlcRuntimeException(String.format("Unexpected 
dataType :%s. Want %s", attribute.getValue(), dataType));
+                }
+                dataTypeValidated = true;
+            } else if (attribute.getName().getLocalPart().equals("bitLength")) 
{
+                if 
(!attribute.getValue().equals(Integer.valueOf(bitLength).toString())) {
+                    throw new PlcRuntimeException(String.format("Unexpected 
bitLength '%s'. Want '%d'", attribute.getValue(), bitLength));
+                }
+                bitLengthValidate = true;
+            }
+        }
+        if (!dataTypeValidated) {
+            throw new PlcRuntimeException("required attribute dataType 
missing");
+        }
+        if (!bitLengthValidate) {
+            throw new PlcRuntimeException("required attribute bitLength 
missing");
+        }
+        return true;
+    }
+
+    private String sanitizeLogicalName(String logicalName) {
+        if (logicalName.equals("")) {
+            return "value";
+        }
+        return logicalName;
+    }
+}
diff --git 
a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferXmlBased.java
 
b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferXmlBased.java
index 6d32130..4b2b8b7 100644
--- 
a/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferXmlBased.java
+++ 
b/plc4j/spi/src/main/java/org/apache/plc4x/java/spi/generation/WriteBufferXmlBased.java
@@ -42,6 +42,8 @@ public class WriteBufferXmlBased implements WriteBuffer {
 
     Document document;
 
+    int pos = 1;
+
     public WriteBufferXmlBased() {
         DocumentBuilderFactory documentBuilderFactory = 
DocumentBuilderFactory.newInstance();
         try {
@@ -54,7 +56,7 @@ public class WriteBufferXmlBased implements WriteBuffer {
 
     @Override
     public int getPos() {
-        return 0;
+        return pos/8;
     }
 
     @Override
@@ -64,137 +66,97 @@ public class WriteBufferXmlBased implements WriteBuffer {
 
     @Override
     public void writeBit(String logicalName, boolean value) throws 
ParseException {
-        Element element = 
document.createElement(sanitizeLogicalName(logicalName));
-        element.setAttribute("dataType", "bit");
-        element.setAttribute("bitLength", "1");
-        
element.appendChild(document.createTextNode(Boolean.valueOf(value).toString()));
-        stack.peek().appendChild(element);
+        String dataType = "bit";
+        int bitLength = 1;
+        String data = Boolean.valueOf(value).toString();
+        createAndAppend(logicalName, dataType, bitLength, data);
+        move(1);
     }
 
     @Override
     public void writeUnsignedByte(String logicalName, int bitLength, byte 
value) throws ParseException {
-        Element element = 
document.createElement(sanitizeLogicalName(logicalName));
-        element.setAttribute("dataType", "uint8");
-        element.setAttribute("bitLength", String.valueOf(bitLength));
-        
element.appendChild(document.createTextNode(Byte.valueOf(value).toString()));
-        stack.peek().appendChild(element);
+        createAndAppend(logicalName, "uint8", bitLength, 
Byte.valueOf(value).toString());
+        move(bitLength);
     }
 
     @Override
     public void writeUnsignedShort(String logicalName, int bitLength, short 
value) throws ParseException {
-        Element element = 
document.createElement(sanitizeLogicalName(logicalName));
-        element.setAttribute("dataType", "uint16");
-        element.setAttribute("bitLength", String.valueOf(bitLength));
-        
element.appendChild(document.createTextNode(Short.valueOf(value).toString()));
-        stack.peek().appendChild(element);
+        createAndAppend(logicalName, "uint16", bitLength, 
Short.valueOf(value).toString());
+        move(bitLength);
     }
 
     @Override
     public void writeUnsignedInt(String logicalName, int bitLength, int value) 
throws ParseException {
-        Element element = 
document.createElement(sanitizeLogicalName(logicalName));
-        element.setAttribute("dataType", "uint32");
-        element.setAttribute("bitLength", String.valueOf(bitLength));
-        
element.appendChild(document.createTextNode(Integer.valueOf(value).toString()));
-        stack.peek().appendChild(element);
+        createAndAppend(logicalName, "uint32", bitLength, 
Integer.valueOf(value).toString());
+        move(bitLength);
     }
 
     @Override
     public void writeUnsignedLong(String logicalName, int bitLength, long 
value) throws ParseException {
-        Element element = 
document.createElement(sanitizeLogicalName(logicalName));
-        element.setAttribute("dataType", "uint64");
-        element.setAttribute("bitLength", String.valueOf(bitLength));
-        
element.appendChild(document.createTextNode(Long.valueOf(value).toString()));
-        stack.peek().appendChild(element);
+        createAndAppend(logicalName, "uint64", bitLength, 
Long.valueOf(value).toString());
+        move(bitLength);
     }
 
     @Override
     public void writeUnsignedBigInteger(String logicalName, int bitLength, 
BigInteger value) throws ParseException {
-        Element element = 
document.createElement(sanitizeLogicalName(logicalName));
-        element.setAttribute("dataType", "bigInt");
-        element.setAttribute("bitLength", String.valueOf(bitLength));
-        element.appendChild(document.createTextNode(value.toString()));
-        stack.peek().appendChild(element);
+        createAndAppend(logicalName, "bigInt", bitLength, value.toString());
+        move(bitLength);
     }
 
     @Override
     public void writeByte(String logicalName, int bitLength, byte value) 
throws ParseException {
-        Element element = 
document.createElement(sanitizeLogicalName(logicalName));
-        element.setAttribute("dataType", "int8");
-        element.setAttribute("bitLength", String.valueOf(bitLength));
-        
element.appendChild(document.createTextNode(Byte.valueOf(value).toString()));
-        stack.peek().appendChild(element);
+        createAndAppend(logicalName, "int8", bitLength, 
Byte.valueOf(value).toString());
+        move(bitLength);
     }
 
     @Override
     public void writeShort(String logicalName, int bitLength, short value) 
throws ParseException {
-        Element element = 
document.createElement(sanitizeLogicalName(logicalName));
-        element.setAttribute("dataType", "int16");
-        element.setAttribute("bitLength", String.valueOf(bitLength));
-        
element.appendChild(document.createTextNode(Short.valueOf(value).toString()));
-        stack.peek().appendChild(element);
+        createAndAppend(logicalName, "int16", bitLength, 
Short.valueOf(value).toString());
+        move(bitLength);
     }
 
     @Override
     public void writeInt(String logicalName, int bitLength, int value) throws 
ParseException {
-        Element element = 
document.createElement(sanitizeLogicalName(logicalName));
-        element.setAttribute("dataType", "int32");
-        element.setAttribute("bitLength", String.valueOf(bitLength));
-        
element.appendChild(document.createTextNode(Integer.valueOf(value).toString()));
-        stack.peek().appendChild(element);
+        createAndAppend(logicalName, "int32", bitLength, 
Integer.valueOf(value).toString());
+        move(bitLength);
     }
 
     @Override
     public void writeLong(String logicalName, int bitLength, long value) 
throws ParseException {
-        Element element = 
document.createElement(sanitizeLogicalName(logicalName));
-        element.setAttribute("dataType", "int64");
-        element.setAttribute("bitLength", String.valueOf(bitLength));
-        
element.appendChild(document.createTextNode(Long.valueOf(value).toString()));
-        stack.peek().appendChild(element);
+        createAndAppend(logicalName, "int64", bitLength, 
Long.valueOf(value).toString());
+        move(bitLength);
     }
 
     @Override
     public void writeBigInteger(String logicalName, int bitLength, BigInteger 
value) throws ParseException {
-        Element element = 
document.createElement(sanitizeLogicalName(logicalName));
-        element.setAttribute("dataType", "bigInt");
-        element.setAttribute("bitLength", String.valueOf(bitLength));
-        element.appendChild(document.createTextNode(value.toString()));
-        stack.peek().appendChild(element);
+        createAndAppend(logicalName, "bigInt", bitLength, value.toString());
+        move(bitLength);
     }
 
     @Override
     public void writeFloat(String logicalName, float value, int bitsExponent, 
int bitsMantissa) throws ParseException {
-        Element element = 
document.createElement(sanitizeLogicalName(logicalName));
-        element.setAttribute("dataType", "float32");
-        element.setAttribute("bitLength", String.valueOf((value < 0 ? 1 : 0) + 
bitsExponent + bitsMantissa));
-        
element.appendChild(document.createTextNode(Float.valueOf(value).toString()));
-        stack.peek().appendChild(element);
+        int bitLength = (value < 0 ? 1 : 0) + bitsExponent + bitsMantissa;
+        createAndAppend(logicalName, "float32", bitLength, 
Float.valueOf(value).toString());
+        move(bitLength);
     }
 
     @Override
     public void writeDouble(String logicalName, double value, int 
bitsExponent, int bitsMantissa) throws ParseException {
-        Element element = 
document.createElement(sanitizeLogicalName(logicalName));
-        element.setAttribute("dataType", "float64");
-        element.setAttribute("bitLength", String.valueOf((value < 0 ? 1 : 0) + 
bitsExponent + bitsMantissa));
-        
element.appendChild(document.createTextNode(Double.valueOf(value).toString()));
-        stack.peek().appendChild(element);
+        int bitLength = (value < 0 ? 1 : 0) + bitsExponent + bitsMantissa;
+        createAndAppend(logicalName, "float64", bitLength, 
Double.valueOf(value).toString());
+        move(bitLength);
     }
 
     @Override
     public void writeBigDecimal(String logicalName, int bitLength, BigDecimal 
value) throws ParseException {
-        Element element = 
document.createElement(sanitizeLogicalName(logicalName));
-        element.setAttribute("dataType", "bigFloat");
-        element.setAttribute("bitLength", String.valueOf(bitLength));
-        element.appendChild(document.createTextNode(value.toString()));
-        stack.peek().appendChild(element);
+        createAndAppend(logicalName, "bigFloat", bitLength, value.toString());
+        move(bitLength);
     }
 
     @Override
     public void writeString(String logicalName, int bitLength, String 
encoding, String value) throws ParseException {
-        Element element = 
document.createElement(sanitizeLogicalName(logicalName));
-        element.setAttribute("dataType", "string");
-        element.setAttribute("bitLength", String.valueOf(bitLength));
-        element.appendChild(document.createTextNode(value));
-        stack.peek().appendChild(element);
+        createAndAppend(logicalName, "string", bitLength, value);
+        move(bitLength);
     }
 
     @Override
@@ -230,6 +192,17 @@ public class WriteBufferXmlBased implements WriteBuffer {
         }
     }
 
+    private void move(int bits) {
+        pos += bits;
+    }
+
+    private void createAndAppend(String logicalName, String dataType, int 
bitLength, String data) {
+        Element element = 
document.createElement(sanitizeLogicalName(logicalName));
+        element.setAttribute("dataType", dataType);
+        element.setAttribute("bitLength", String.valueOf(bitLength));
+        element.appendChild(document.createTextNode(data));
+        stack.peek().appendChild(element);
+    }
 
     private String sanitizeLogicalName(String logicalName) {
         if (logicalName.equals("")) {

Reply via email to