@NotNull
  public String getNamespaceByPrefix(String prefix) {
    final PsiElement parent = getParent();
    LOG.assertTrue(parent.isValid());
    BidirectionalMap<String, String> map = initNamespaceMaps(parent);
    if (map != null) {
      final String ns = map.get(prefix);
      if (ns != null) return ns;
    }
    if (parent instanceof XmlTag) return ((XmlTag) parent).getNamespaceByPrefix(prefix);
    // The prefix 'xml' is by definition bound to the namespace name
    // http://www.w3.org/XML/1998/namespace. It MAY, but need not, be declared
    if (XML_NS_PREFIX.equals(prefix)) return XmlUtil.XML_NAMESPACE_URI;

    if (prefix.length() > 0 && !hasNamespaceDeclarations() && getNamespacePrefix().equals(prefix)) {
      // When there is no namespace declarations then qualified names should be just used in dtds
      // this implies that we may have "" namespace prefix ! (see last paragraph in Namespaces in
      // Xml, Section 5)

      String result =
          ourGuard.doPreventingRecursion(
              "getNsByPrefix",
              true,
              new Computable<String>() {
                @Override
                public String compute() {
                  final String nsFromEmptyPrefix = getNamespaceByPrefix("");
                  final XmlNSDescriptor nsDescriptor = getNSDescriptor(nsFromEmptyPrefix, false);
                  final XmlElementDescriptor descriptor =
                      nsDescriptor != null
                          ? nsDescriptor.getElementDescriptor(XmlTagImpl.this)
                          : null;
                  final String nameFromRealDescriptor =
                      descriptor != null
                              && descriptor.getDeclaration() != null
                              && descriptor.getDeclaration().isPhysical()
                          ? descriptor.getName()
                          : "";
                  if (nameFromRealDescriptor.equals(getName())) return nsFromEmptyPrefix;
                  return XmlUtil.EMPTY_URI;
                }
              });
      if (result != null) {
        return result;
      }
    }
    return XmlUtil.EMPTY_URI;
  }