Manufactura industrial
Internet industrial de las cosas | Materiales industriales | Mantenimiento y reparación de equipos | Programación industrial |
home  MfgRobots >> Manufactura industrial >  >> Manufacturing Technology >> Tecnología Industrial

Poblar una clase C++ desde XML usando IXMLSerializable en PLCnext

Resumen

¿Sabía que las Clases Comunes de PLCnext tienen soporte integrado para serialización XML? Este artículo muestra cómo usar la interfaz IXmlSerializable para poblar los datos en una clase C++.

Puede encontrar la descripción de la Interfaz en la documentación API de las Clases Comunes de PLCnext.

Requisitos

Este artículo fue escrito con la siguiente configuración:

PLCnext Firmware: 2020.6 LTS
PLCnext C++ SDK para Linux 64 Bit 2020.6 LTS

Los datos

Queremos poblar 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>

La notación $ARP_DATA_DIR$ es un marcador de posición para variable de entorno, en este caso ARP_DATA_DIR. Puede encontrar las variables de entorno Arp definidas en su archivo de configuración del dispositivo en el objetivo /etc/plcnext/Device.acf.settings.

Para poder leer los datos de un archivo XML tenemos que implementar la interfaz IXMLSerializable 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;

    // Interfaz IXMLSerializable
  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;

    // Los datos
  public:
    Arp::String DnsName{""};
    std::vector<Arp::String> FileList;

    // Métodos de apoyo
  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 los métodos ReadXml y WriteXml.

El método WriteXml es directo, no queremos escribir, solo queremos leer los datos del archivo XML. El método ReadXml se llama 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) {
    // sin operación
    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) {
    // Usar 'context.ResolvePath' para reemplazar marcadores de posición en la ruta.
    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 la clase XMLConfigDocument en el método LoadConfig para cargar los datos en nuestra clase.

void MyComponent::LoadConfig() {
  // cargar configuración del proyecto aquí
  using namespace Arp::System::Commons;
  this->log.Info("LoadConfig");
  
  // El primer argumento debe coincidir con el nombre del elemento raíz XML.
  // Nuestra instancia MyConfiguration this->config será poblada.
  Xml::XmlConfigDocument configDoc("MyConfigDocument", this->config);
  
  if (!Io::File::Exists(this->settingsPath)) {
    this->log.Error("El archivo de configuración '{}' no existe.", 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

  1. Uso de la interfaz de línea de comandos con SPICE
  2. Cómo la Tecnología Transforma la Manufactura: De Impresión 3D a Gemelos Digitales
  3. Cómo elegir el motor a prueba de explosiones adecuado: guía completa
  4. Tipos de Matrices (Dies) en Fabricación: Estampado, Estirado y Fundición
  5. Cómo los puntos de prueba mejoran las pruebas de PCB y la eficiencia de producción
  6. Cómo la automatización está transformando la fabricación: Impulsando eficiencia y reduciendo costos
  7. Los beneficios de la Realidad Aumentada en la Industria 4.0
  8. Dominando Java BufferedReader: Manejo Eficiente de Flujos de Caracteres
  9. Dominando las operaciones de archivos en Java con java.io: creación, lectura, escritura y eliminación
  10. Interfaz vs Clase Abstracta en Java: Cómo elegir la abstracción correcta
  11. Entendiendo las Interfaces en Java: Definiciones, Usos y Buenas Prácticas