PLCnextでIXMLSerializableを使用してXMLからC++クラスを生成
概要
PLCnext Common ClassesにXMLシリアル化のビルトインサポートがあることをご存知ですか?この記事では、IXmlSerializableインターフェースを使用して、C++クラスのデータをXMLから読み込む方法を紹介します。
インターフェースの説明は、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$表記は環境変数のプレースホルダーで、この場合はARP_DATA_DIRです。定義済みのArp環境変数は、ターゲットのデバイス設定ファイル/etc/plcnext/Device.acf.settingsで確認できます。
XMLファイルからデータを読み取るには、クラスでIXMLSerializableインターフェースを実装する必要があります。シンプルにするため、クラスにはDNS名とファイルパスのベクターという2つのデータ要素のみを持たせます。
#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インターフェース 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; // データ public: Arp::String DnsName{""}; std::vector<Arp::String> FileList; // 補助メソッド 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) { // 操作なし 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) { // 'context.ResolvePath'を使用してパス内のプレースホルダーを置換 auto file = Arp::String(context.ResolvePath(reader.GetAttributeValue<Arp::String>("path"))); this->FileList.push_back(file); reader.ReadEndElement(); } } // namespace MyComponent
データの読み取り
これで、LoadConfigメソッドでXMLConfigDocumentクラスとともにクラスを使用して、データをクラスに読み込むことができます。
void MyComponent::LoadConfig() { // プロジェクト設定をここで読み込み using namespace Arp::System::Commons; this->log.Info("LoadConfig"); // 第1引数はXMLルート要素名と一致する必要があります。 // MyConfigurationインスタンスthis->configにデータが読み込まれます。 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()); } }
産業技術
- SPICEでのコマンドラインインターフェースの使い方
- テクノロジーが製造業を変革:3Dプリンティングからデジタルツインまで
- 適切な防爆モーター選定の包括的ガイド
- 製造用ダイ(金型)の種類:プレス/引抜き/鋳造ダイの違いと分類
- テストポイントがPCBテストと生産効率を向上させる仕組み
- 自動化が製造業を変革:効率向上とコスト削減の実現
- インダストリー4.0における拡張現実(AR)のメリット
- Java BufferedReader完全ガイド:効率的な文字ストリーム処理
- Javaファイル操作のマスター:java.ioによる作成・読み取り・書き込み・削除
- Java インターフェース vs 抽象クラス:適切な抽象化の選び方
- Javaインターフェース完全ガイド: 定義・実装・多重継承・タグインターフェース