docs: public static IQ parseIQ(XmlPullParser parser, XmlEnvironment outerXmlEnvironment) throws Exception {
          ParserUtils.assertAtStartTag(parser);
          final int initialDepth = parser.getDepth();
          XmlEnvironment iqXmlEnvironment = XmlEnvironment.from(parser, outerXmlEnvironment);
          IQ iqPacket = null;
          StanzaError.Builder error = null;
  
          final String id = parser.getAttributeValue("", "id");
          final Jid to = ParserUtils.getJidAttribute(parser, "to");
          final Jid from = ParserUtils.getJidAttribute(parser, "from");
          final IQ.Type type = IQ.Type.fromString(parser.getAttributeValue("", "type"));
  
          outerloop: while (true) {
              int eventType = parser.next();
  
              switch (eventType) {
              case XmlPullParser.START_TAG:
                  String elementName = parser.getName();
                  String namespace = parser.getNamespace();
                  switch (elementName) {
                  case "error":
                      error = PacketParserUtils.parseError(parser, iqXmlEnvironment);
                      break;
                  // Otherwise, see if there is a registered provider for
                  // this element name and namespace.
                  default:
                      IQProvider<IQ> provider = ProviderManager.getIQProvider(elementName, namespace);
                      if (provider != null) {
                              iqPacket = provider.parse(parser, outerXmlEnvironment);
                      }
                      // Note that if we reach this code, it is guranteed that the result IQ contained a child element
                      // (RFC 6120 § 8.2.3 6) because otherwhise we would have reached the END_TAG first.
                      else {
                          // No Provider found for the IQ stanza, parse it to an UnparsedIQ instance
                          // so that the content of the IQ can be examined later on
                          iqPacket = new UnparsedIQ(elementName, namespace, parseElement(parser));
                      }
                      break;
                  }
                  break;
              case XmlPullParser.END_TAG:
                  if (parser.getDepth() == initialDepth) {
                      break outerloop;
                  }
                  break;
              }
          }
          // Decide what to do when an IQ packet was not understood
          if (iqPacket == null) {
              switch (type) {
              case error:
                  // If an IQ packet wasn't created above, create an empty error IQ packet.
                  iqPacket = new ErrorIQ(error);
                  break;
              case result:
                  iqPacket = new EmptyResultIQ();
                  break;
              default:
                  break;
              }
          }
  
          // Set basic values on the iq packet.
          iqPacket.setStanzaId(id);
          iqPacket.setTo(to);
          iqPacket.setFrom(from);
          iqPacket.setType(type);
          iqPacket.setError(error);
  
          return iqPacket;
      }