virDomainDeviceInfoParseXML(virDomainXMLOptionPtr xmlopt,
                            xmlNodePtr node,
                            virDomainDeviceInfoPtr info,
                            unsigned int flags)
{
    xmlNodePtr cur;
    xmlNodePtr address = NULL;
    xmlNodePtr master = NULL;
    xmlNodePtr alias = NULL;
    xmlNodePtr boot = NULL;
    xmlNodePtr rom = NULL;
    int ret = -1;
    g_autofree char *romenabled = NULL;
    g_autofree char *rombar = NULL;
    g_autofree char *aliasStr = NULL;

    virDomainDeviceInfoClear(info);

    cur = node->children;
    while (cur != NULL) {
        if (cur->type == XML_ELEMENT_NODE) {
            if (alias == NULL &&
                virXMLNodeNameEqual(cur, "alias")) {
                alias = cur;
            } else if (address == NULL &&
                       virXMLNodeNameEqual(cur, "address")) {
                address = cur;
            } else if (master == NULL &&
                       virXMLNodeNameEqual(cur, "master")) {
                master = cur;
            } else if (boot == NULL &&
                       (flags & VIR_DOMAIN_DEF_PARSE_ALLOW_BOOT) &&
                       virXMLNodeNameEqual(cur, "boot")) {
                boot = cur;
            } else if (rom == NULL &&
                       (flags & VIR_DOMAIN_DEF_PARSE_ALLOW_ROM) &&
                       virXMLNodeNameEqual(cur, "rom")) {
                rom = cur;
            }
        }
        cur = cur->next;
    }

    if (alias) {
        aliasStr = virXMLPropString(alias, "name");

        if (!(flags & VIR_DOMAIN_DEF_PARSE_INACTIVE) ||
            (xmlopt->config.features & VIR_DOMAIN_DEF_FEATURE_USER_ALIAS &&
             virDomainDeviceAliasIsUserAlias(aliasStr) &&
             strspn(aliasStr, USER_ALIAS_CHARS) == strlen(aliasStr)))
            info->alias = g_steal_pointer(&aliasStr);
    }

    if (master) {
        info->mastertype = VIR_DOMAIN_CONTROLLER_MASTER_USB;
        if (virDomainDeviceUSBMasterParseXML(master, &info->master.usb) < 0)
            goto cleanup;
    }

    if (boot) {
        if (virDomainDeviceBootParseXML(boot, info))
            goto cleanup;
    }

    if (rom) {
        if ((romenabled = virXMLPropString(rom, "enabled")) &&
            ((info->romenabled = virTristateBoolTypeFromString(romenabled)) <= 0)) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown rom enabled value '%s'"), romenabled);
            goto cleanup;
        }
        if ((rombar = virXMLPropString(rom, "bar")) &&
            ((info->rombar = virTristateSwitchTypeFromString(rombar)) <= 0)) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("unknown rom bar value '%s'"), rombar);
            goto cleanup;
        }
        info->romfile = virXMLPropString(rom, "file");

        if (info->romenabled == VIR_TRISTATE_BOOL_NO &&
            (info->rombar != VIR_TRISTATE_SWITCH_ABSENT || info->romfile)) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("ROM tuning is not supported when ROM is disabled"));
            goto cleanup;
        }
    }

    if (address &&
        virDomainDeviceAddressParseXML(address, info) < 0)
        goto cleanup;


    ret = 0;
 cleanup:
    if (ret < 0)
        virDomainDeviceInfoClear(info);
    return ret;
}