Use la interfaz IXMLSerializable para completar una clase desde un archivo XML
Resumen
¿Sabía que las clases comunes de PLCnext tienen compatibilidad integrada con la serialización XML? Este artículo muestra cómo usar el IXmlSerializable
interfaz para llenar los datos en una clase c++.
Puede encontrar la descripción de la interfaz en la documentación de la API de las clases comunes de PLCnext.
Requisitos
Este artículo fue escrito con la siguiente configuración:
Firmware PLCnext:2020.6 LTS PLCnext C++ SDK para Linux 64 bits 2020.6 LTS
Los datos
Queremos llenar nuestra clase con el siguiente archivo de configuración.
<?xml version="1.0" encoding="UTF-8"?> <MyConfigDocument schemaVersion="1.0"> <Server dnsName="server.domain.tld" /> <FileList> <File path="$ARP_DATA_DIR$/Services/MyComponent/file1.txt" /> <File path="$ARP_DATA_DIR$/Services/MyComponent/file2.txt" /> </FileList> </MyConfigDocument>
El $ARP_DATA_DIR$
la notación es un marcador de posición para la variable de entorno, en este caso ARP_DATA_DIR
. Puede encontrar las variables de entorno Arp definidas en el archivo de configuración de su dispositivo en el destino /etc/plcnext/Device.acf.settings
.
Para poder leer los datos de un archivo XML tenemos que implementar el IXMLSerializable
interfaz para nuestra clase. Para mantenerlo simple, nuestra clase tiene solo dos elementos de datos, un nombre DNS y un vector de rutas de archivos.
#pragma once #include "Arp/System/Core/Arp.h" #include "Arp/System/Commons/Xml/IXmlSerializable.hpp" #include "vector" namespace MyComponent { class MyConfiguration : public Arp::System::Commons::Xml::IXmlSerializable { public: MyConfiguration() = default; ~MyConfiguration() = default; // IXMLSerializable interface public: void ReadXml(Arp::System::Commons::Xml::XmlReader& reader, Arp::System::Commons::Xml::XmlSerializationContext& context) override; void WriteXml(Arp::System::Commons::Xml::XmlWriter& writer, Arp::System::Commons::Xml::XmlSerializationContext& context) override; // The data public: Arp::String DnsName{""}; std::vector<Arp::String> FileList; // Some supporting methods private: void readFileList(Arp::System::Commons::Xml::XmlReader& reader, Arp::System::Commons::Xml::XmlSerializationContext& context); void readFile(Arp::System::Commons::Xml::XmlReader& reader, Arp::System::Commons::Xml::XmlSerializationContext& context); }; } // namespace MyComponent
Implementación
Debemos implementar el ReadXml
y WriteXml
Métodos.
El WriteXml
El método es sencillo, no queremos escribir, solo queremos leer los datos del archivo XML. El ReadXml
Se llama al método si queremos leer los datos del archivo XML.
#include "MyConfiguration.hpp"
namespace MyComponent
{
void MyConfiguration::WriteXml(Arp::System::Commons::Xml::XmlWriter& writer, Arp::System::Commons::Xml::XmlSerializationContext& context)
{
// no operation.
return;
}
void MyConfiguration::ReadXml(Arp::System::Commons::Xml::XmlReader& reader, Arp::System::Commons::Xml::XmlSerializationContext& context)
{
Arp::String elementName;
while (reader.TryReadStartElement(elementName))
{
if (elementName == Arp::System::Commons::Xml::XmlSerializationContext::IncludesXmlName)
{
context.ReadIncludesElement(reader);
}
else if (elementName == "Server")
{
this->DnsName = reader.GetAttributeValue<Arp::String>("dnsName");
reader.ReadEndElement();
}
else if (elementName == "FileList")
{
this->readFileList(reader, context);
}
else
{
context.InvalidXmlElementOccurs(reader, elementName);
reader.ReadEndElement();
}
}
}
void MyConfiguration::readFileList(Arp::System::Commons::Xml::XmlReader& reader, Arp::System::Commons::Xml::XmlSerializationContext& context)
{
if (reader.IsEmptyElement()){
return;
}
if (reader.ReadToDescendant("File"))
{
this->readFile(reader, context);
while (reader.ReadToNextSibling("File"))
{
this->readFile(reader, context);
}
}
else
{
reader.ReadEndElement();
}
}
void MyConfiguration::readFile(Arp::System::Commons::Xml::XmlReader& reader, Arp::System::Commons::Xml::XmlSerializationContext& context)
{
// Use 'context.ResolvePath' to replace placeholders in the path.
auto file = Arp::String(context.ResolvePath(reader.GetAttributeValue<Arp::String>("path")));
this->FileList.push_back(file);
reader.ReadEndElement();
}
} // namespace MyComponent
Leer los datos
Ahora podemos usar nuestra clase con el XMLConfigDocument
class en el Método LoadConfig para cargar los datos en nuestra clase.
void MyComponent::LoadConfig() { // load project config here using namespace Arp::System::Commons; this->log.Info("LoadConfig"); // Fist argument has to match the XML root element name. // Our MyConfiguration instance this->config will be populated. Xml::XmlConfigDocument configDoc("MyConfigDocument", this->config); if (!Io::File::Exists(this->settingsPath)) { this->log.Error("Configuration file '{}' does not exist.", this->settingsPath); return; } try { configDoc.Load(this->settingsPath); } catch (const Arp::Exception& e) { this->log.Error(e.GetMessage()); throw InvalidConfigException(e.GetMessage()); } }
Tecnología Industrial
- La interfaz de línea de comandos
- El uso cada vez mayor de la tecnología en la industria manufacturera
- Clase Java BufferedReader
- Clase de archivo Java
- Interfaz vs clase abstracta en Java:¿cuál es la diferencia?
- Java - Interfaces
- La guía completa para elegir un motor a prueba de explosiones
- Diferentes tipos de uso de troqueles en la fabricación
- ¿Cuál es el uso de los puntos de prueba en un circuito de PCB?
- El uso creciente de la automatización en la fabricación
- ¿Por qué utilizar Realidad Aumentada en la industria?