createElementNS(self::XML_NAMESPACE, self::XML_NAMESPACE_PREFIX . ':' . $name); if ($value !== null) { $textNode = $doc->createTextNode($value); $element->appendChild($textNode); } foreach ($attributes as $attrName => $attrValue) { $element->setAttribute($attrName, $attrValue); } return $element; } protected function createDsElement(\DOMDocument $doc, string $name, ?string $value = null, array $attributes = []): \DOMElement { $element = $doc->createElementNS(self::XML_DS_NAMESPACE, self::XML_DS_NAMESPACE_PREFIX . ':' . $name); if ($value !== null) { $textNode = $doc->createTextNode($value); $element->appendChild($textNode); } foreach ($attributes as $attrName => $attrValue) { $element->setAttribute($attrName, $attrValue); } return $element; } protected function getElementValue(\DOMElement $parent, string $name, string $namespace = self::XML_NAMESPACE): ?string { $elements = $parent->getElementsByTagNameNS($namespace, $name); if ($elements->length > 0) { return $elements->item(0)->textContent; } return null; } abstract public function toXml(\DOMDocument $doc): \DOMElement; public static function fromXml($xml): self { if ($xml instanceof \DOMElement) { return static::fromDOMElement($xml); } if (!is_string($xml)) { throw new \InvalidArgumentException('Input must be either a string or DOMElement'); } $doc = new \DOMDocument(); $doc->formatOutput = true; $doc->preserveWhiteSpace = false; if (!$doc->loadXML($xml)) { throw new \DOMException('Failed to load XML: Invalid XML format'); } return static::fromDOMElement($doc->documentElement); } abstract public static function fromDOMElement(\DOMElement $element): self; }