def load_graphml(
    filepath: str | Path | None = None,
    *,
    graphml_str: str | None = None,
    node_dtypes: dict[str, Any] | None = None,
    edge_dtypes: dict[str, Any] | None = None,
    graph_dtypes: dict[str, Any] | None = None,
) -> nx.MultiDiGraph:
    """
    Load an OSMnx-saved GraphML file from disk or GraphML string.

    This function converts node, edge, and graph-level attributes (serialized
    as strings) to their appropriate data types. These can be customized as
    needed by passing in dtypes arguments providing types or custom converter
    functions. For example, if you want to convert some attribute's values to
    `bool`, consider using the built-in `ox.io._convert_bool_string` function
    to properly handle "True"/"False" string literals as True/False booleans:
    `ox.load_graphml(fp, node_dtypes={my_attr: ox.io._convert_bool_string})`.

    If you manually configured the `all_oneway=True` setting, you may need to
    manually specify here that edge `oneway` attributes should be type `str`.

    Note that you must pass one and only one of `filepath` or `graphml_str`.
    If passing `graphml_str`, you may need to decode the bytes read from your
    file before converting to string to pass to this function.

    Parameters
    ----------
    filepath
        Path to the GraphML file.
    graphml_str
        Valid and decoded string representation of a GraphML file's contents.
    node_dtypes
        Dict of node attribute names:types to convert values' data types. The
        type can be a type or a custom string converter function.
    edge_dtypes
        Dict of edge attribute names:types to convert values' data types. The
        type can be a type or a custom string converter function.
    graph_dtypes
        Dict of graph-level attribute names:types to convert values' data
        types. The type can be a type or a custom string converter function.

    Returns
    -------
    G
        The loaded MultiDiGraph.
    """
    if (filepath is None and graphml_str is None) or (
        filepath is not None and graphml_str is not None
    ):  # pragma: no cover
        msg = "You must pass one and only one of `filepath` or `graphml_str`."
        raise ValueError(msg)

    # specify default graph/node/edge attribute values' data types
    default_graph_dtypes = {
        "consolidated": _convert_bool_string,
        "simplified": _convert_bool_string,
    }
    default_node_dtypes = {
        "elevation": float,
        "elevation_res": float,
        "osmid": int,
        "street_count": int,
        "x": float,
        "y": float,
    }
    default_edge_dtypes = {
        "bearing": float,
        "grade": float,
        "grade_abs": float,
        "length": float,
        "oneway": _convert_bool_string,
        "osmid": int,
        "reversed": _convert_bool_string,
        "speed_kph": float,
        "travel_time": float,
    }

    # override default graph/node/edge attr types with user-passed types, if any
    if graph_dtypes is not None:
        default_graph_dtypes.update(graph_dtypes)
    if node_dtypes is not None:
        default_node_dtypes.update(node_dtypes)
    if edge_dtypes is not None:
        default_edge_dtypes.update(edge_dtypes)

    if filepath is not None:
        # read the graphml file from disk
        source = filepath
        G = nx.read_graphml(
            Path(filepath),
            node_type=default_node_dtypes["osmid"],
            force_multigraph=True,
        )
    else:
        # parse the graphml string
        source = "string"
        G = nx.parse_graphml(
            graphml_str,
            node_type=default_node_dtypes["osmid"],
            force_multigraph=True,
        )

    # convert graph/node/edge attribute data types
    msg = "Converting node, edge, and graph-level attribute data types"
    utils.log(msg, level=lg.INFO)
    G = _convert_graph_attr_types(G, default_graph_dtypes)
    G = _convert_node_attr_types(G, default_node_dtypes)
    G = _convert_edge_attr_types(G, default_edge_dtypes)

    msg = f"Loaded graph with {len(G)} nodes and {len(G.edges)} edges from {str(source)!r}"
    utils.log(msg, level=lg.INFO)
    return G

    Load an OSMnx-saved GraphML file from disk or GraphML string.

    This function converts node, edge, and graph-level attributes (serialized
    as strings) to their appropriate data types. These can be customized as
    needed by passing in dtypes arguments providing types or custom converter
    functions. For example, if you want to convert some attribute's values to
    `bool`, consider using the built-in `ox.io._convert_bool_string` function
    to properly handle "True"/"False" string literals as True/False booleans:
    `ox.load_graphml(fp, node_dtypes={my_attr: ox.io._convert_bool_string})`.

    If you manually configured the `all_oneway=True` setting, you may need to
    manually specify here that edge `oneway` attributes should be type `str`.

    Note that you must pass one and only one of `filepath` or `graphml_str`.
    If passing `graphml_str`, you may need to decode the bytes read from your
    file before converting to string to pass to this function.

    Parameters
    ----------
    filepath
        Path to the GraphML file.
    graphml_str
        Valid and decoded string representation of a GraphML file's contents.
    node_dtypes
        Dict of node attribute names:types to convert values' data types. The
        type can be a type or a custom string converter function.
    edge_dtypes
        Dict of edge attribute names:types to convert values' data types. The
        type can be a type or a custom string converter function.
    graph_dtypes
        Dict of graph-level attribute names:types to convert values' data
        types. The type can be a type or a custom string converter function.

    Returns
    -------
    G
        The loaded MultiDiGraph.
    
osmnx/io.py