使用 IXMLSerializable 接口从 XML 文件填充类
摘要
您知道 PLCnext 公共类内置了对 XML 序列化的支持吗?本文介绍如何使用 IXmlSerializable 在 c++ 类中填充数据的接口。
接口说明可以在PLCnext Common Classes的API文档中找到。
要求
本文是使用以下设置编写的:
PLCnext 固件:2020.6 LTS PLCnext C++ SDK for Linux 64 Bit 2020.6 LTS
数据
我们想用以下配置文件填充我们的类。
<?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>
$ARP_DATA_DIR$ notation 是环境变量的占位符,在本例中为 ARP_DATA_DIR .您可以在目标 /etc/plcnext/Device.acf.settings 上的设备设置文件中找到已定义的 Arp 环境变量 .
为了能够从 XML 文件中读取数据,我们必须实现 IXMLSerializable 我们类的接口。为了简单起见,我们的类只有两个数据元素,一个 DNS 名称和一个文件路径向量。
#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 实现
我们必须实现 ReadXml 和 WriteXml 方法。
WriteXml 方法很简单,我们不想写我们只想从 XML 文件中读取数据。 ReadXml 如果我们想从 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 读取数据
我们现在可以将我们的类与 XMLConfigDocument 一起使用 类中的LoadConfig方法来加载我们类中的数据。
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());
}
} 工业技术