New service for converting TDFs to/from XML documents

This commit is contained in:
Nav
2024-02-09 23:32:58 +00:00
parent c563443737
commit 5ea04625ef
4 changed files with 978 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
<?php
namespace Targets\TargetDescriptionFiles\Services\Xml\Exceptions;
class XmlParsingException extends \Exception
{}

View File

@@ -0,0 +1,417 @@
<?php
namespace Targets\TargetDescriptionFiles\Services\Xml;
use DOMDocument;
use DOMNode;
use DOMNodeList;
use DOMElement;
use Targets\TargetDescriptionFiles\Services\StringService;
use Targets\TargetDescriptionFiles\Services\Xml\Exceptions\XmlParsingException;
use Targets\TargetDescriptionFiles\AddressSpace;
use Targets\TargetDescriptionFiles\BitField;
use Targets\TargetDescriptionFiles\MemorySegment;
use Targets\TargetDescriptionFiles\MemorySegmentSection;
use Targets\TargetDescriptionFiles\MemorySegmentType;
use Targets\TargetDescriptionFiles\Module;
use Targets\TargetDescriptionFiles\Peripheral;
use Targets\TargetDescriptionFiles\PhysicalInterface;
use Targets\TargetDescriptionFiles\Property;
use Targets\TargetDescriptionFiles\PropertyGroup;
use Targets\TargetDescriptionFiles\Register;
use Targets\TargetDescriptionFiles\RegisterGroup;
use Targets\TargetDescriptionFiles\RegisterGroupReference;
use Targets\TargetDescriptionFiles\Signal;
use Targets\TargetDescriptionFiles\Pinout;
use Targets\TargetDescriptionFiles\PinoutType;
use Targets\TargetDescriptionFiles\Pin;
use Targets\TargetDescriptionFiles\Variant;
require_once __DIR__ . '/../StringService.php';
require_once __DIR__ . '/../../TargetDescriptionFile.php';
require_once __DIR__ . '/Exceptions/XmlParsingException.php';
/**
* The FromXmlService facilitates the conversion of XML documents to TargetDescriptionFile objects.
*/
class FromXmlService
{
private StringService $stringService;
public function __construct(?StringService $stringService = null)
{
$this->stringService = $stringService ?? new StringService();
}
public function getDeviceElement(DOMDocument $document): DOMElement
{
$deviceElement = $document->getElementsByTagName('device')->item(0);
if (!$deviceElement instanceof DOMElement) {
throw new XmlParsingException('Missing device element');
}
return $deviceElement;
}
public function getNodeAttributesByName(DOMNode $node): array
{
$output = [];
foreach ($node->attributes as $attribute) {
/** @var \DOMAttr $attribute */
$output[$attribute->name] = $attribute->value;
}
return $output;
}
public function getDeviceElementsFromXPath(string $expression, DOMDocument $document): DOMNodeList
{
$elements = (new \DOMXPath($document))->query('/device/' . $expression);
if ($elements === false) {
throw new \Exception('Failed to evaluate XPath expression - malformed expression');
}
return $elements;
}
public function propertyGroupFromElement(DOMElement $element): PropertyGroup
{
$attributes = $this->getNodeAttributesByName($element);
$output = new PropertyGroup($attributes['key'] ?? null, [], []);
foreach ($element->childNodes as $childNode) {
if (!$childNode instanceof DOMElement) {
continue;
}
if ($childNode->nodeName === 'property') {
$output->properties[] = $this->propertyFromElement($childNode);
continue;
}
if ($childNode->nodeName === 'property-group') {
$output->subPropertyGroups[] = $this->propertyGroupFromElement($childNode);
}
}
return $output;
}
public function propertyFromElement(DOMElement $element): Property
{
$attributes = $this->getNodeAttributesByName($element);
return new Property(
$attributes['key'] ?? null,
$attributes['value'] ?? null,
);
}
public function addressSpaceFromElement(DOMElement $element): AddressSpace
{
$attributes = $this->getNodeAttributesByName($element);
$output = new AddressSpace(
$attributes['key'] ?? null,
$this->stringService->tryStringToInt($attributes['start'] ?? null),
$this->stringService->tryStringToInt($attributes['size'] ?? null),
$attributes['endianness'] ?? null,
);
foreach ($element->childNodes as $childNode) {
if (!$childNode instanceof DOMElement) {
continue;
}
if ($childNode->nodeName === 'memory-segment') {
$output->memorySegments[] = $this->memorySegmentFromElement($childNode);
}
}
return $output;
}
public function memorySegmentFromElement(DOMElement $element): MemorySegment
{
$attributes = $this->getNodeAttributesByName($element);
$output = new MemorySegment(
$attributes['key'] ?? null,
$attributes['name'] ?? null,
MemorySegmentType::tryFrom($attributes['type'] ?? null),
$this->stringService->tryStringToInt($attributes['start'] ?? null),
$this->stringService->tryStringToInt($attributes['size'] ?? null),
$this->stringService->tryStringToInt($attributes['page-size'] ?? null),
$attributes['rw'] ?? null,
[]
);
foreach ($element->childNodes as $childNode) {
if (!$childNode instanceof DOMElement) {
continue;
}
if ($childNode->nodeName === 'section') {
$output->sections[] = $this->memorySegmentSectionFromElement($childNode);
}
}
return $output;
}
public function memorySegmentSectionFromElement(DOMElement $element): MemorySegmentSection
{
$attributes = $this->getNodeAttributesByName($element);
$output = new MemorySegmentSection(
$attributes['key'] ?? null,
$attributes['name'] ?? null,
$this->stringService->tryStringToInt($attributes['start'] ?? null),
$this->stringService->tryStringToInt($attributes['size'] ?? null),
[]
);
foreach ($element->childNodes as $childNode) {
if (!$childNode instanceof DOMElement) {
continue;
}
if ($childNode->nodeName === 'section') {
$output->subSections[] = $this->memorySegmentSectionFromElement($childNode);
}
}
return $output;
}
public function physicalInterfaceFromElement(DOMElement $element): PhysicalInterface
{
$attributes = $this->getNodeAttributesByName($element);
return new PhysicalInterface(
$attributes['name'] ?? null,
$attributes['type'] ?? null,
);
}
public function moduleFromElement(DOMElement $element): Module
{
$attributes = $this->getNodeAttributesByName($element);
$output = new Module(
$attributes['key'] ?? null,
$attributes['name'] ?? null,
$attributes['description'] ?? null,
[]
);
foreach ($element->childNodes as $childNode) {
if (!$childNode instanceof DOMElement) {
continue;
}
if ($childNode->nodeName === 'register-group') {
$output->registerGroups[] = $this->registerGroupFromElement($childNode);
}
}
return $output;
}
public function registerGroupFromElement(DOMElement $element): RegisterGroup
{
$attributes = $this->getNodeAttributesByName($element);
$output = new RegisterGroup(
$attributes['key'] ?? null,
$attributes['name'] ?? null,
$this->stringService->tryStringToInt($attributes['offset'] ?? null),
[],
[],
[]
);
foreach ($element->childNodes as $childNode) {
if (!$childNode instanceof DOMElement) {
continue;
}
if ($childNode->nodeName === 'register') {
$output->registers[] = $this->registerFromElement($childNode);
continue;
}
if ($childNode->nodeName === 'register-group') {
$output->subGroups[] = $this->registerGroupFromElement($childNode);
continue;
}
if ($childNode->nodeName === 'register-group-reference') {
$output->subGroupReferences[] = $this->registerGroupReferenceFromElement($childNode);
}
}
return $output;
}
public function registerGroupReferenceFromElement(DOMElement $element): RegisterGroupReference
{
$attributes = $this->getNodeAttributesByName($element);
return new RegisterGroupReference(
$attributes['key'] ?? null,
$attributes['name'] ?? null,
$attributes['register-group-key'] ?? null,
$this->stringService->tryStringToInt($attributes['offset'] ?? null),
$attributes['description'] ?? null
);
}
public function registerFromElement(DOMElement $element): Register
{
$attributes = $this->getNodeAttributesByName($element);
$output = new Register(
$attributes['key'] ?? null,
$attributes['name'] ?? null,
$attributes['description'] ?? null,
$this->stringService->tryStringToInt($attributes['offset'] ?? null),
$this->stringService->tryStringToInt($attributes['size'] ?? null),
$this->stringService->tryStringToInt($attributes['initial-value'] ?? null),
$attributes['rw'] ?? null,
isset($attributes['alternative']) ? trim($attributes['alternative']) === 'true' : null,
[]
);
foreach ($element->childNodes as $childNode) {
if (!$childNode instanceof DOMElement) {
continue;
}
if ($childNode->nodeName === 'bit-field') {
$output->bitFields[] = $this->bitFieldFromElement($childNode);
}
}
return $output;
}
public function bitFieldFromElement(DOMElement $element): BitField
{
$attributes = $this->getNodeAttributesByName($element);
return new BitField(
$attributes['key'] ?? null,
$attributes['name'] ?? null,
$attributes['description'] ?? null,
$this->stringService->tryStringToInt($attributes['mask'] ?? null),
$attributes['rw'] ?? null
);
}
public function peripheralFromElement(DOMElement $element): Peripheral
{
$attributes = $this->getNodeAttributesByName($element);
$output = new Peripheral(
$attributes['key'] ?? null,
$attributes['name'] ?? null,
$attributes['module-key'] ?? null,
[],
[]
);
foreach ($element->childNodes as $childNode) {
if (!$childNode instanceof DOMElement) {
continue;
}
if ($childNode->nodeName === 'register-group-reference') {
$output->registerGroupReferences[] = $this->registerGroupReferenceFromElement($childNode);
continue;
}
if ($childNode->nodeName === 'signal') {
$output->signals[] = $this->signalFromElement($childNode);
}
}
$signalsElements = $element->getElementsByTagName('signals');
if ($signalsElements->count() > 1) {
throw new XmlParsingException('Unexpected number of "signals" elements');
}
$signalElement = $signalsElements->item(0);
if ($signalElement instanceof DOMElement) {
foreach ($signalElement->childNodes as $childNode) {
if (!$childNode instanceof DOMElement) {
continue;
}
if ($childNode->nodeName === 'signal') {
$output->signals[] = $this->signalFromElement($childNode);
}
}
}
return $output;
}
public function signalFromElement(DOMElement $element): Signal
{
$attributes = $this->getNodeAttributesByName($element);
return new Signal(
$attributes['pad-id'] ?? null,
$this->stringService->tryStringToInt($attributes['index'] ?? null),
$attributes['function'] ?? null,
$attributes['group'] ?? null,
$attributes['field'] ?? null
);
}
public function pinoutFromElement(DOMElement $element): Pinout
{
$attributes = $this->getNodeAttributesByName($element);
$output = new Pinout(
$attributes['key'] ?? null,
$attributes['name'] ?? null,
PinoutType::tryFrom($attributes['type'] ?? null),
$attributes['function'] ?? null,
[]
);
foreach ($element->childNodes as $childNode) {
if (!$childNode instanceof DOMElement) {
continue;
}
if ($childNode->nodeName === 'pin') {
$output->pins[] = $this->pinFromElement($childNode);
}
}
return $output;
}
public function pinFromElement(DOMElement $element): Pin
{
$attributes = $this->getNodeAttributesByName($element);
return new Pin(
$attributes['position'] ?? null,
$attributes['pad'] ?? null
);
}
public function variantFromElement(DOMElement $element): Variant
{
$attributes = $this->getNodeAttributesByName($element);
return new Variant(
$attributes['name'] ?? null,
$attributes['pinout-key'] ?? null,
$attributes['package'] ?? null
);
}
}

View File

@@ -0,0 +1,351 @@
<?php
namespace Targets\TargetDescriptionFiles\Services\Xml;
use DOMDocument;
use DOMElement;
use Targets\TargetDescriptionFiles\AddressSpace;
use Targets\TargetDescriptionFiles\BitField;
use Targets\TargetDescriptionFiles\MemorySegment;
use Targets\TargetDescriptionFiles\MemorySegmentSection;
use Targets\TargetDescriptionFiles\Module;
use Targets\TargetDescriptionFiles\Peripheral;
use Targets\TargetDescriptionFiles\PhysicalInterface;
use Targets\TargetDescriptionFiles\Pin;
use Targets\TargetDescriptionFiles\Pinout;
use Targets\TargetDescriptionFiles\Property;
use Targets\TargetDescriptionFiles\PropertyGroup;
use Targets\TargetDescriptionFiles\Register;
use Targets\TargetDescriptionFiles\RegisterGroup;
use Targets\TargetDescriptionFiles\RegisterGroupReference;
use Targets\TargetDescriptionFiles\Services\StringService;
use Targets\TargetDescriptionFiles\Signal;
use Targets\TargetDescriptionFiles\Variant;
require_once __DIR__ . '/../StringService.php';
require_once __DIR__ . '/../../TargetDescriptionFile.php';
require_once __DIR__ . '/Exceptions/XmlParsingException.php';
/**
* The ToXmlService facilitates the conversion of TargetDescriptionFile objects to XML documents.
*/
class ToXmlService
{
private StringService $stringService;
public function __construct(?StringService $stringService = null)
{
$this->stringService = $stringService ?? new StringService();
}
public function propertyGroupToXml(PropertyGroup $propertyGroup, DOMDocument $document): DOMElement
{
$element = $document->createElement('property-group');
$element->setAttribute('key', strtolower($propertyGroup->key));
foreach ($propertyGroup->subPropertyGroups as $subPropertyGroup) {
$element->append($this->propertyGroupToXml($subPropertyGroup, $document));
}
foreach ($propertyGroup->properties as $property) {
$element->append($this->propertyToXml($property, $document));
}
return $element;
}
public function propertyToXml(Property $property, DOMDocument $document): DOMElement
{
$element = $document->createElement('property');
$element->setAttribute('key', strtolower($property->key));
$element->setAttribute('value', $property->value);
return $element;
}
public function addressSpaceToXml(AddressSpace $addressSpace, DOMDocument $document): DOMElement
{
$element = $document->createElement('address-space');
$element->setAttribute('key', strtolower($addressSpace->key));
$element->setAttribute('start', $this->stringService->tryIntToHex($addressSpace->startAddress, 8));
$element->setAttribute('size', $addressSpace->size);
if (!empty($addressSpace->endianness)) {
$element->setAttribute('endianness', strtolower($addressSpace->endianness));
}
foreach ($addressSpace->memorySegments as $memorySegment) {
$element->append($this->memorySegmentToXml($memorySegment, $document));
}
return $element;
}
public function memorySegmentToXml(MemorySegment $memorySegment, DOMDocument $document): DOMElement
{
$element = $document->createElement('memory-segment');
$element->setAttribute('key', strtolower($memorySegment->key));
$element->setAttribute('name', $memorySegment->name);
$element->setAttribute('type', $memorySegment->type->value ?? '');
$element->setAttribute('start', $this->stringService->tryIntToHex($memorySegment->startAddress, 8));
$element->setAttribute('size', $memorySegment->size);
if (!empty($memorySegment->pageSize)) {
$element->setAttribute('page-size', $memorySegment->pageSize);
}
if (!empty($memorySegment->access)) {
$element->setAttribute('rw', $memorySegment->access);
}
foreach ($memorySegment->sections as $segmentSection) {
$element->append($this->memorySegmentSectionToXml($segmentSection, $document));
}
return $element;
}
public function memorySegmentSectionToXml(MemorySegmentSection $section, DOMDocument $document): DOMElement
{
$element = $document->createElement('section');
$element->setAttribute('key', strtolower($section->key));
$element->setAttribute('name', $section->name);
$element->setAttribute('start', $this->stringService->tryIntToHex($section->startAddress, 8));
$element->setAttribute('size', $section->size);
foreach ($section->subSections as $section) {
$element->append($this->memorySegmentSectionToXml($section, $document));
}
return $element;
}
public function physicalInterfaceToXml(PhysicalInterface $physicalInterface, DOMDocument $document): DOMElement
{
$element = $document->createElement('physical-interface');
$element->setAttribute('name', $physicalInterface->name);
$element->setAttribute('type', $physicalInterface->type);
return $element;
}
public function peripheralToXml(Peripheral $peripheral, DOMDocument $document): DOMElement
{
$element = $document->createElement('peripheral');
$element->setAttribute('key', $peripheral->key);
$element->setAttribute('name', $peripheral->name);
$element->setAttribute('module-key', $peripheral->moduleKey);
foreach ($peripheral->registerGroupReferences as $registerGroupReference) {
$element->append($this->registerGroupReferenceToXml($registerGroupReference, $document));
}
if (!empty($peripheral->signals)) {
$signalsElement = $document->createElement('signals');
foreach ($peripheral->signals as $signal) {
$signalsElement->append($this->signalToXml($signal, $document));
}
$element->append($signalsElement);
}
return $element;
}
public function signalToXml(Signal $signal, DOMDocument $document): DOMElement
{
$element = $document->createElement('signal');
$element->setAttribute('pad-id', $signal->padId);
if ($signal->index !== null) {
$element->setAttribute('index', $signal->index);
}
if ($signal->function !== null) {
$element->setAttribute('function', $signal->function);
}
if ($signal->group !== null) {
$element->setAttribute('group', $signal->group);
}
if ($signal->field !== null) {
$element->setAttribute('field', $signal->field);
}
return $element;
}
public function moduleToXml(Module $module, DOMDocument $document): DOMElement
{
$element = $document->createElement('module');
$element->setAttribute('key', $module->key);
$element->setAttribute('name', $module->name);
$element->setAttribute('description', trim($module->description));
foreach ($module->registerGroups as $registerGroup) {
$element->append($this->registerGroupToXml($registerGroup, $document));
}
return $element;
}
public function registerGroupToXml(RegisterGroup $registerGroup, DOMDocument $document): DOMElement
{
$element = $document->createElement('register-group');
$element->setAttribute('key', $registerGroup->key);
$element->setAttribute('name', $registerGroup->name);
if ($registerGroup->offset !== null) {
$element->setAttribute('offset', $this->stringService->tryIntToHex($registerGroup->offset));
}
/*
* A register group can have registers, register groups (subgroups) and register group references as children.
*
* We want these to appear in the order of their offset, in the XML. So we group them into a single array,
* sort them, then generate the XML elements.
*/
$children = array_merge(
$registerGroup->registers,
$registerGroup->subGroups,
$registerGroup->subGroupReferences
);
usort(
$children,
fn (
RegisterGroup|RegisterGroupReference|Register $childA,
RegisterGroup|RegisterGroupReference|Register $childB
): bool => $childA->offset > $childB->offset
);
foreach ($children as $child) {
/**
* @var RegisterGroup|RegisterGroupReference|Register $child
*/
if ($child instanceof Register) {
$element->append($this->registerToXml($child, $document));
continue;
}
if ($child instanceof RegisterGroup) {
$element->append($this->registerGroupToXml($child, $document));
continue;
}
if ($child instanceof RegisterGroupReference) {
$element->append($this->registerGroupReferenceToXml($child, $document));
}
}
return $element;
}
public function registerGroupReferenceToXml(
RegisterGroupReference $registerGroupReference,
DOMDocument $document
): DOMElement {
$element = $document->createElement('register-group-reference');
$element->setAttribute('key', $registerGroupReference->key);
$element->setAttribute('name', $registerGroupReference->name);
if (!empty($registerGroupReference->description)) {
$element->setAttribute('description', $registerGroupReference->description);
}
$element->setAttribute('register-group-key', $registerGroupReference->registerGroupKey);
$element->setAttribute('offset', $this->stringService->tryIntToHex($registerGroupReference->offset));
return $element;
}
public function registerToXml(Register $register, DOMDocument $document): DOMElement
{
$element = $document->createElement('register');
$element->setAttribute('key', $register->key);
$element->setAttribute('name', $register->name);
if (!empty($register->description)) {
$element->setAttribute('description', trim($register->description));
}
$element->setAttribute('offset', $this->stringService->tryIntToHex($register->offset));
$element->setAttribute('size', $register->size);
if ($register->initialValue !== null) {
$element->setAttribute('initial-value', $this->stringService->tryIntToHex($register->initialValue));
}
if (!empty($register->access)) {
$element->setAttribute('rw', $register->access);
}
if ($register->alternative !== null) {
$element->setAttribute('alternative', $register->alternative ? 'true' : 'false');
}
foreach ($register->bitFields as $bitField) {
$element->append($this->bitFieldToXml($bitField, $document));
}
return $element;
}
public function bitFieldToXml(BitField $bitField, DOMDocument $document): DOMElement
{
$element = $document->createElement('bit-field');
$element->setAttribute('key', $bitField->key);
$element->setAttribute('name', $bitField->name);
if (!empty($bitField->description)) {
$element->setAttribute('description', trim($bitField->description));
}
$element->setAttribute('mask', $this->stringService->tryIntToHex($bitField->mask));
if (!empty($bitField->access)) {
$element->setAttribute('rw', $bitField->access);
}
return $element;
}
public function pinoutToXml(Pinout $pinout, DOMDocument $document): DOMElement
{
$element = $document->createElement('pinout');
$element->setAttribute('key', $pinout->key);
$element->setAttribute('name', $pinout->name);
$element->setAttribute('type', $pinout->type->value ?? '');
if (!empty($pinout->function)) {
$element->setAttribute('function', $pinout->function);
}
foreach ($pinout->pins as $pin) {
$element->append($this->pinToXml($pin, $document));
}
return $element;
}
public function pinToXml(Pin $pin, DOMDocument $document): DOMElement
{
$element = $document->createElement('pin');
$element->setAttribute('position', $pin->position);
$element->setAttribute('pad', $pin->pad);
return $element;
}
public function variantToXml(Variant $variant, DOMDocument $document): DOMElement
{
$element = $document->createElement('variant');
$element->setAttribute('name', $variant->name);
$element->setAttribute('pinout-key', $variant->pinoutKey);
$element->setAttribute('package', $variant->package);
return $element;
}
}

View File

@@ -0,0 +1,205 @@
<?php
namespace Targets\TargetDescriptionFiles\Services\Xml;
use DOMDocument;
use DOMException;
use Targets\TargetDescriptionFiles\TargetDescriptionFile;
use Targets\TargetDescriptionFiles\Avr8\Avr8TargetDescriptionFile;
use Targets\TargetDescriptionFiles\Services\Xml\Exceptions\XmlParsingException;
use Targets\TargetDescriptionFiles\TargetFamily;
require_once __DIR__ . '/FromXmlService.php';
require_once __DIR__ . '/ToXmlService.php';
require_once __DIR__ . '/../../TargetDescriptionFile.php';
require_once __DIR__ . '/Exceptions/XmlParsingException.php';
/**
* The XmlService provides conversion of TargetDescriptionFile objects to/from XML documents.
*
* This can be used to:
* - Construct a new instance of TargetDescriptionFile, from an XML document.
* - Convert a TargetDescriptionFile instance to an XML document.
*/
class XmlService
{
private FromXmlService $fromXmlService;
private ToXmlService $toXmlService;
public function __construct(?FromXmlService $fromXmlService = null, ?ToXmlService $toXmlService = null)
{
$this->fromXmlService = $fromXmlService ?? new FromXmlService();
$this->toXmlService = $toXmlService ?? new ToXmlService();
}
/**
* Constructs a TargetDescriptionFile from the given XML document.
*
* @param DOMDocument $document
* The XML document from which to construct the TargetDescriptionFile.
*
* @return TargetDescriptionFile
* The constructed TargetDescriptionFile.
*/
public function fromXml(DOMDocument $document): TargetDescriptionFile
{
$deviceElement = $this->fromXmlService->getDeviceElement($document);
$deviceAttributesByName = $this->fromXmlService->getNodeAttributesByName($deviceElement);
$targetFamily = TargetFamily::tryFrom($deviceAttributesByName['family'] ?? null);
if (!$targetFamily instanceof TargetFamily) {
throw new XmlParsingException('Failed to resolve target family - missing/invalid family attribute');
}
$tdf = match ($targetFamily) {
TargetFamily::AVR_8 => new Avr8TargetDescriptionFile(),
default => new TargetDescriptionFile(),
};
$tdf->deviceAttributesByName = $deviceAttributesByName;
$propertyGroupElements = $this->fromXmlService->getDeviceElementsFromXPath(
'property-groups/property-group',
$document
);
foreach ($propertyGroupElements as $element) {
$tdf->propertyGroups[] = $this->fromXmlService->propertyGroupFromElement($element);
}
$addressSpaceElements = $this->fromXmlService->getDeviceElementsFromXPath(
'address-spaces/address-space',
$document
);
foreach ($addressSpaceElements as $element) {
$tdf->addressSpaces[] = $this->fromXmlService->addressSpaceFromElement($element);
}
$physicalInterfaceElements = $this->fromXmlService->getDeviceElementsFromXPath(
'physical-interfaces/physical-interface',
$document
);
foreach ($physicalInterfaceElements as $element) {
$tdf->physicalInterfaces[] = $this->fromXmlService->physicalInterfaceFromElement($element);
}
$peripheralElements = $this->fromXmlService->getDeviceElementsFromXPath(
'peripherals/peripheral',
$document
);
foreach ($peripheralElements as $element) {
$tdf->peripherals[] = $this->fromXmlService->peripheralFromElement($element);
}
$moduleElements = $this->fromXmlService->getDeviceElementsFromXPath(
'modules/module',
$document
);
foreach ($moduleElements as $element) {
$tdf->modules[] = $this->fromXmlService->moduleFromElement($element);
}
$pinoutElements = $this->fromXmlService->getDeviceElementsFromXPath(
'pinouts/pinout',
$document
);
foreach ($pinoutElements as $element) {
$tdf->pinouts[] = $this->fromXmlService->pinoutFromElement($element);
}
$variantElements = $this->fromXmlService->getDeviceElementsFromXPath(
'variants/variant',
$document
);
foreach ($variantElements as $element) {
$tdf->variants[] = $this->fromXmlService->variantFromElement($element);
}
return $tdf;
}
/**
* Generates an XML document from the given TDF.
*
* @param TargetDescriptionFile $tdf
* The TDF from which to generate the XML document.
*
* @return DOMDocument
* The generated XML document.
*
* @throws DOMException
*/
public function toXml(TargetDescriptionFile $tdf): DOMDocument
{
$document = new DOMDocument('1.0', 'UTF-8');
$deviceElement = $document->createElement('device');
$deviceElement->setAttribute('name', $tdf->getName());
$deviceElement->setAttribute('family', $tdf->getFamily()->value ?? '');
$deviceElement->setAttribute('configuration-value', $tdf->getConfigurationValue());
$architecture = $tdf->getArchitecture();
if (!empty($architecture)) {
$deviceElement->setAttribute('architecture', $architecture);
}
$vendor = $tdf->getVendor();
if (!empty($vendor)) {
$deviceElement->setAttribute('vendor', $vendor);
}
foreach ($tdf->getAdditionalDeviceAttributes() as $attrName => $attrValue) {
$deviceElement->setAttribute($attrName, $attrValue);
}
$propertyGroupsElement = $document->createElement('property-groups');
foreach ($tdf->propertyGroups as $propertyGroup) {
$propertyGroupsElement->append($this->toXmlService->propertyGroupToXml($propertyGroup, $document));
}
$deviceElement->append($propertyGroupsElement);
$addressSpacesElement = $document->createElement('address-spaces');
foreach ($tdf->addressSpaces as $addressSpace) {
$addressSpacesElement->append($this->toXmlService->addressSpaceToXml($addressSpace, $document));
}
$deviceElement->append($addressSpacesElement);
$interfacesElement = $document->createElement('physical-interfaces');
foreach ($tdf->physicalInterfaces as $interface) {
$interfacesElement->append($this->toXmlService->physicalInterfaceToXml($interface, $document));
}
$deviceElement->append($interfacesElement);
$peripheralsElement = $document->createElement('peripherals');
foreach ($tdf->peripherals as $peripheral) {
$peripheralsElement->append($this->toXmlService->peripheralToXml($peripheral, $document));
}
$deviceElement->append($peripheralsElement);
$modulesElement = $document->createElement('modules');
foreach ($tdf->modules as $module) {
$modulesElement->append($this->toXmlService->moduleToXml($module, $document));
}
$deviceElement->append($modulesElement);
$pinoutsElement = $document->createElement('pinouts');
foreach ($tdf->pinouts as $pinout) {
$pinoutsElement->append($this->toXmlService->pinoutToXml($pinout, $document));
}
$deviceElement->append($pinoutsElement);
$variantsElement = $document->createElement('variants');
foreach ($tdf->variants as $variant) {
$variantsElement->append($this->toXmlService->variantToXml($variant, $document));
}
$deviceElement->append($variantsElement);
$document->append($deviceElement);
return $document;
}
}