1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
|
import functools
import re
from typing import Dict, Optional, Tuple
from xsdata.models.enums import Namespace
from xsdata.utils import text
__uri_ignore__ = ("www", "xsd", "wsdl")
URI_REGEX = re.compile(
r"^(([a-zA-Z][0-9a-zA-Z+\\-\\.]*:)?"
r"/{0,2}[0-9a-zA-Z;/?:@&=+$\\.\\-_!~*'()%]+)?"
r"(#[0-9a-zA-Z;/?:@&=+$\\.\\-_!~*'()%]+)?$"
)
def load_prefix(uri: str, ns_map: Dict) -> Optional[str]:
"""Get or create a prefix for the given uri in the prefix-URI namespace
mapping."""
for prefix, ns in ns_map.items():
if ns == uri:
return prefix
return generate_prefix(uri, ns_map)
def generate_prefix(uri: str, ns_map: Dict) -> str:
"""Generate and add a prefix for the given uri in the prefix-URI namespace
mapping."""
namespace = Namespace.get_enum(uri)
if namespace:
prefix = namespace.prefix
else:
number = len(ns_map)
prefix = f"ns{number}"
ns_map[prefix] = uri
return prefix
def prefix_exists(uri: str, ns_map: Dict) -> bool:
"""Check if the uri exists in the prefix-URI namespace mapping."""
return uri in ns_map.values()
def is_default(uri: str, ns_map: Dict) -> bool:
"""Check if the uri exists and it has no prefix."""
return any(uri == ns and not prefix for prefix, ns in ns_map.items())
def clean_prefixes(ns_map: Dict) -> Dict:
"""Remove default namespace if it's also assigned to a prefix."""
result = {}
for prefix, ns in ns_map.items():
if ns:
prefix = prefix or None
if prefix not in result:
result[prefix] = ns
default_ns = result.get(None)
if default_ns and any(prefix and ns == default_ns for prefix, ns in result.items()):
result.pop(None)
return result
def clean_uri(namespace: str) -> str:
"""Remove common prefixes and suffixes from a uri string."""
if namespace[:2] == "##":
namespace = namespace[2:]
left, right = text.split(namespace)
if left == "urn":
namespace = right
elif left in ("http", "https"):
namespace = right[2:]
return "_".join(x for x in namespace.split(".") if x not in __uri_ignore__)
def real_xsi_type(qname: str, target_qname: Optional[str]) -> Optional[str]:
"""Determine if the given target qualified name should be used to define a
derived type."""
return target_qname if target_qname != qname else None
@functools.lru_cache(maxsize=50)
def build_qname(tag_or_uri: Optional[str], tag: Optional[str] = None) -> str:
"""Create namespace qualified strings."""
if not tag_or_uri:
if not tag:
raise ValueError("Invalid input both uri and tag are empty.")
return tag
return f"{{{tag_or_uri}}}{tag}" if tag else tag_or_uri
@functools.lru_cache(maxsize=50)
def split_qname(tag: str) -> Tuple:
"""Split namespace qualified strings."""
if tag[0] == "{":
left, right = text.split(tag[1:], "}")
if left:
return left, right
return None, tag
def target_uri(tag: str) -> Optional[str]:
return split_qname(tag)[0]
def local_name(tag: str) -> str:
return split_qname(tag)[1]
NCNAME_PUNCTUATION = {"\u00B7", "\u0387", ".", "-", "_"}
def is_ncname(name: Optional[str]) -> bool:
"""Verify given string is a valid ncname."""
if not name:
return False
char = name[0]
if not char.isalpha() and char != "_":
return False
for char in name[1:]:
if char.isalpha() or char.isdigit() or char in NCNAME_PUNCTUATION:
continue
else:
return False
return True
def is_uri(uri: Optional[str]) -> bool:
"""Verify given string is a valid uri."""
return bool(URI_REGEX.search(uri)) if uri else False
@functools.lru_cache(maxsize=50)
def to_package_name(uri: Optional[str]) -> str:
"""Util method to convert a namespace to a dot style package name."""
if not uri:
return ""
# Remove scheme
domain_sep = "."
if uri.startswith("http://"):
uri = uri[7:]
elif uri.startswith("urn:"):
uri = uri[4:]
domain_sep = "-"
if uri.startswith("xmlns:"):
uri = uri[6:]
uri = uri.replace(":", "/")
# Remote target
pos = uri.find("#")
if pos > 0:
uri = uri[:pos]
tokens = [token for token in uri.split("/") if token.strip()]
if not tokens:
return ""
# Remove extension
if len(tokens) > 1:
last = tokens[-1]
pos = tokens[-1].rfind(".")
if pos > 0:
tokens[-1] = last[:pos]
# Remove port from domain
domain = tokens.pop(0)
pos = domain.find(":")
if pos > 0:
domain = domain[:pos]
# Remove www from domain
if domain.startswith("www"):
domain = domain[3:]
for part in domain.split(domain_sep):
tokens.insert(0, part)
return ".".join(token for token in tokens if token)
|