virDomainTPMDefParseXML(virDomainXMLOptionPtr xmlopt,
                        xmlNodePtr node,
                        xmlXPathContextPtr ctxt,
                        unsigned int flags)
{
    virDomainTPMDefPtr def;
    VIR_XPATH_NODE_AUTORESTORE(ctxt);
    int nbackends;
    g_autofree char *path = NULL;
    g_autofree char *model = NULL;
    g_autofree char *backend = NULL;
    g_autofree char *version = NULL;
    g_autofree char *secretuuid = NULL;
    g_autofree xmlNodePtr *backends = NULL;

    if (VIR_ALLOC(def) < 0)
        return NULL;

    model = virXMLPropString(node, "model");
    if (model != NULL &&
        (def->model = virDomainTPMModelTypeFromString(model)) < 0) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unknown TPM frontend model '%s'"), model);
        goto error;
    }

    ctxt->node = node;

    if ((nbackends = virXPathNodeSet("./backend", ctxt, &backends)) < 0)
        goto error;

    if (nbackends > 1) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("only one TPM backend is supported"));
        goto error;
    }

    if (nbackends == 0) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing TPM device backend"));
        goto error;
    }

    if (!(backend = virXMLPropString(backends[0], "type"))) {
        virReportError(VIR_ERR_XML_ERROR, "%s",
                       _("missing TPM device backend type"));
        goto error;
    }

    if ((def->type = virDomainTPMBackendTypeFromString(backend)) < 0) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Unknown TPM backend type '%s'"),
                       backend);
        goto error;
    }

    version = virXMLPropString(backends[0], "version");
    if (!version) {
        def->version = VIR_DOMAIN_TPM_VERSION_DEFAULT;
    } else {
        if ((def->version = virDomainTPMVersionTypeFromString(version)) < 0) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("Unsupported TPM version '%s'"),
                           version);
            goto error;
        }
    }

    switch (def->type) {
    case VIR_DOMAIN_TPM_TYPE_PASSTHROUGH:
        path = virXPathString("string(./backend/device/@path)", ctxt);
        if (!path)
            path = g_strdup(VIR_DOMAIN_TPM_DEFAULT_DEVICE);
        def->data.passthrough.source.data.file.path = g_steal_pointer(&path);
        def->data.passthrough.source.type = VIR_DOMAIN_CHR_TYPE_DEV;
        break;
    case VIR_DOMAIN_TPM_TYPE_EMULATOR:
        secretuuid = virXPathString("string(./backend/encryption/@secret)", ctxt);
        if (secretuuid) {
            if (virUUIDParse(secretuuid, def->data.emulator.secretuuid) < 0) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Unable to parse secret uuid '%s'"), secretuuid);
                goto error;
            }
            def->data.emulator.hassecretuuid = true;
        }
        break;
    case VIR_DOMAIN_TPM_TYPE_LAST:
        goto error;
    }

    if (virDomainDeviceInfoParseXML(xmlopt, node, &def->info, flags) < 0)
        goto error;

    return def;

 error:
    virDomainTPMDefFree(def);
    return NULL;
}