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
The following commit(s) were added to refs/heads/develop by this push:
new ab34489 plc4j: switch xml writer to a stax based implementation to
align to the reader
ab34489 is described below
commit ab34489c435f552369c0d602a394fafab546f54c
Author: Sebastian Rühl <[email protected]>
AuthorDate: Tue Apr 20 18:33:25 2021 +0200
plc4j: switch xml writer to a stax based implementation to align to the
reader
---
plc4j/drivers/s7/src/test/java/S7IoTest.java | 106 +++++++++---------
.../java/spi/generation/WriteBufferXmlBased.java | 122 +++++++++++++--------
2 files changed, 132 insertions(+), 96 deletions(-)
diff --git a/plc4j/drivers/s7/src/test/java/S7IoTest.java
b/plc4j/drivers/s7/src/test/java/S7IoTest.java
index a96e27c..ee2a43c 100644
--- a/plc4j/drivers/s7/src/test/java/S7IoTest.java
+++ b/plc4j/drivers/s7/src/test/java/S7IoTest.java
@@ -42,59 +42,59 @@ public class S7IoTest {
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" +
+ " <protocolId dataType=\"uint8\"
bitLength=\"8\">3</protocolId>\n" +
+ " <reserved dataType=\"uint8\"
bitLength=\"8\">0</reserved>\n" +
+ " <len dataType=\"uint16\" bitLength=\"16\">29</len>\n" +
+ " <COTPPacket>\n" +
+ " <headerLength dataType=\"uint8\"
bitLength=\"8\">5</headerLength>\n" +
+ " <tpduCode dataType=\"uint8\"
bitLength=\"8\">240</tpduCode>\n" +
+ " <COTPPacketData>\n" +
+ " <eot dataType=\"bit\" bitLength=\"1\">false</eot>\n" +
+ " <tpduRef dataType=\"uint8\"
bitLength=\"7\">13</tpduRef>\n" +
+ " </COTPPacketData>\n" +
+ " <parameters>\n" +
+ " <COTPParameter>\n" +
+ " <parameterType dataType=\"uint8\"
bitLength=\"8\">192</parameterType>\n" +
+ " <parameterLength dataType=\"uint8\"
bitLength=\"8\">1</parameterLength>\n" +
+ " <COTPParameterTpduSize>\n" +
+ " <COTPTpduSize dataType=\"int8\" bitLength=\"8\"
stringRepresentation=\"SIZE_4096\">12</COTPTpduSize>\n" +
+ " </COTPParameterTpduSize>\n" +
+ " </COTPParameter>\n" +
+ " </parameters>\n" +
+ " <S7Message>\n" +
+ " <protocolId dataType=\"uint8\"
bitLength=\"8\">50</protocolId>\n" +
+ " <messageType dataType=\"uint8\"
bitLength=\"8\">3</messageType>\n" +
+ " <reserved dataType=\"uint16\"
bitLength=\"16\">0</reserved>\n" +
+ " <tpduReference dataType=\"uint16\"
bitLength=\"16\">11</tpduReference>\n" +
+ " <parameterLength dataType=\"uint16\"
bitLength=\"16\">2</parameterLength>\n" +
+ " <payloadLength dataType=\"uint16\"
bitLength=\"16\">5</payloadLength>\n" +
+ " <S7MessageResponseData>\n" +
+ " <errorClass dataType=\"uint8\"
bitLength=\"8\">0</errorClass>\n" +
+ " <errorCode dataType=\"uint8\"
bitLength=\"8\">0</errorCode>\n" +
+ " </S7MessageResponseData>\n" +
+ " <S7Parameter>\n" +
+ " <parameterType dataType=\"uint8\"
bitLength=\"8\">4</parameterType>\n" +
+ " <S7ParameterReadVarResponse>\n" +
+ " <numItems dataType=\"uint8\"
bitLength=\"8\">1</numItems>\n" +
+ " </S7ParameterReadVarResponse>\n" +
+ " </S7Parameter>\n" +
+ " <S7Payload>\n" +
+ " <S7PayloadReadVarResponse>\n" +
+ " <items>\n" +
+ " <S7VarPayloadDataItem>\n" +
+ " <DataTransportErrorCode dataType=\"uint8\"
bitLength=\"8\" stringRepresentation=\"OK\">255</DataTransportErrorCode>\n" +
+ " <DataTransportSize dataType=\"uint8\"
bitLength=\"8\" stringRepresentation=\"BIT\">3</DataTransportSize>\n" +
+ " <dataLength dataType=\"uint16\"
bitLength=\"16\">1</dataLength>\n" +
+ " <data>\n" +
+ " <value dataType=\"int8\"
bitLength=\"8\">1</value>\n" +
+ " </data>\n" +
+ " <padding></padding>\n" +
+ " </S7VarPayloadDataItem>\n" +
+ " </items>\n" +
+ " </S7PayloadReadVarResponse>\n" +
+ " </S7Payload>\n" +
+ " </S7Message>\n" +
+ " </COTPPacket>\n" +
"</TPKTPacket>\n";
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 4b2b8b7..f052054 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
@@ -19,36 +19,42 @@
package org.apache.plc4x.java.spi.generation;
+import org.apache.commons.lang3.StringUtils;
import org.apache.plc4x.java.api.exceptions.PlcRuntimeException;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.OutputKeys;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
+
+import javax.xml.stream.XMLEventFactory;
+import javax.xml.stream.XMLEventWriter;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.*;
+
import java.io.ByteArrayOutputStream;
+import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Stack;
public class WriteBufferXmlBased implements WriteBuffer {
- Stack<Element> stack;
+ Stack<String> stack;
+
+ ByteArrayOutputStream byteArrayOutputStream;
- Document document;
+ XMLEventFactory xmlEventFactory;
+
+ XMLEventWriter xmlEventWriter;
int pos = 1;
+ int depth = 0;
+
public WriteBufferXmlBased() {
- DocumentBuilderFactory documentBuilderFactory =
DocumentBuilderFactory.newInstance();
+ byteArrayOutputStream = new ByteArrayOutputStream();
+ XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newInstance();
+ xmlEventFactory = XMLEventFactory.newInstance();
try {
- this.document =
documentBuilderFactory.newDocumentBuilder().newDocument();
- } catch (ParserConfigurationException e) {
+ xmlEventWriter =
xmlOutputFactory.createXMLEventWriter(byteArrayOutputStream);
+ } catch (XMLStreamException e) {
throw new PlcRuntimeException(e);
}
this.stack = new Stack<>();
@@ -56,12 +62,21 @@ public class WriteBufferXmlBased implements WriteBuffer {
@Override
public int getPos() {
- return pos/8;
+ return pos / 8;
}
@Override
public void pushContext(String logicalName) {
- stack.push(document.createElement(logicalName));
+ try {
+ indent();
+ depth++;
+ StartElement startElement = xmlEventFactory.createStartElement("",
"", logicalName);
+ xmlEventWriter.add(startElement);
+ newLine();
+ } catch (XMLStreamException e) {
+ throw new PlcRuntimeException(e);
+ }
+ stack.push(logicalName);
}
@Override
@@ -161,33 +176,33 @@ public class WriteBufferXmlBased implements WriteBuffer {
@Override
public void popContext(String logicalName) {
- Element currentContext = stack.pop();
- if (!currentContext.getTagName().equals(logicalName)) {
- throw new PlcRuntimeException("Unexpected pop context '" +
currentContext.getTagName() + '\'');
+ try {
+ depth--;
+ indent();
+ EndElement endElement = xmlEventFactory.createEndElement("", "",
logicalName);
+ xmlEventWriter.add(endElement);
+ newLine();
+ } catch (XMLStreamException e) {
+ throw new PlcRuntimeException(e);
+ }
+
+ String context = stack.pop();
+ if (!context.equals(logicalName)) {
+ throw new PlcRuntimeException("Unexpected pop context '" + context
+ '\'');
}
if (stack.isEmpty()) {
- document.appendChild(currentContext);
- return;
+ try {
+ xmlEventWriter.close();
+ } catch (XMLStreamException e) {
+ throw new PlcRuntimeException(e);
+ }
}
- stack.peek().appendChild(currentContext);
}
public String getXmlString() {
try {
- Transformer transformer =
TransformerFactory.newInstance().newTransformer();
- transformer.setOutputProperty(OutputKeys.INDENT, "yes");
- transformer.setOutputProperty(OutputKeys.METHOD, "xml");
- transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
- transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION,
"yes");
- //transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,
"roles.dtd");
-
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
-
- ByteArrayOutputStream byteArrayOutputStream = new
ByteArrayOutputStream();
- transformer.transform(new DOMSource(document),
- new StreamResult(byteArrayOutputStream));
-
- return byteArrayOutputStream.toString();
- } catch (TransformerException e) {
+ return byteArrayOutputStream.toString("UTF-8");
+ } catch (UnsupportedEncodingException e) {
throw new PlcRuntimeException(e);
}
}
@@ -196,12 +211,33 @@ public class WriteBufferXmlBased implements WriteBuffer {
pos += bits;
}
+ private void newLine() throws XMLStreamException {
+ Characters newLine = xmlEventFactory.createCharacters("\n");
+ xmlEventWriter.add(newLine);
+ }
+
+ private void indent() throws XMLStreamException {
+ Characters indent =
xmlEventFactory.createCharacters(StringUtils.repeat(" ", depth));
+ xmlEventWriter.add(indent);
+ }
+
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);
+ try {
+ indent();
+ StartElement startElement = xmlEventFactory.createStartElement("",
"", sanitizeLogicalName(logicalName));
+ xmlEventWriter.add(startElement);
+ Attribute dataTypeAttribute =
xmlEventFactory.createAttribute("dataType", dataType);
+ xmlEventWriter.add(dataTypeAttribute);
+ Attribute bitLengthAttribute =
xmlEventFactory.createAttribute("bitLength", String.valueOf(bitLength));
+ xmlEventWriter.add(bitLengthAttribute);
+ Characters dataCharacters = xmlEventFactory.createCharacters(data);
+ xmlEventWriter.add(dataCharacters);
+ EndElement endElement = xmlEventFactory.createEndElement("", "",
sanitizeLogicalName(logicalName));
+ xmlEventWriter.add(endElement);
+ newLine();
+ } catch (XMLStreamException e) {
+ throw new PlcRuntimeException(e);
+ }
}
private String sanitizeLogicalName(String logicalName) {