protected EdmAnnotation<?> getAnnotationElements(XMLEvent2 event, XMLEventReader2 reader) {
   StartElement2 annotationStartElement = event.asStartElement();
   QName2 q = annotationStartElement.getName();
   String value = null;
   EdmAnnotationElement<?> element = null;
   List<EdmAnnotation<?>> list = new ArrayList<EdmAnnotation<?>>();
   if (!NON_USER_NAMESPACES.contains(q.getNamespaceUri())) {
     // a user extension
     while (reader.hasNext()) {
       event = reader.nextEvent();
       if (event.isStartElement()) {
         EdmAnnotation<?> childElement = getAnnotationElements(event, reader);
         if (childElement != null) {
           list.add(childElement);
         }
       } else if (event.isCharacters()) {
         value = event.asCharacters().getData().trim();
       } else if (event.isEndElement()) {
         if (value != null) {
           element =
               EdmAnnotation.element(
                   q.getNamespaceUri(), q.getPrefix(), q.getLocalPart(), String.class, value);
         } else {
           element =
               EdmAnnotation.element(
                   q.getNamespaceUri(), q.getPrefix(), q.getLocalPart(), String.class, "");
         }
         element.setAnnotationElements(list);
         element.setAnnotations(getAnnotations(annotationStartElement));
         return element;
       }
     }
   }
   return null;
 }
  public static Iterable<OProperty<?>> parseProperties(
      XMLEventReader2 reader, StartElement2 propertiesElement) {
    List<OProperty<?>> rt = new ArrayList<OProperty<?>>();

    while (reader.hasNext()) {
      XMLEvent2 event = reader.nextEvent();

      if (event.isEndElement()
          && event.asEndElement().getName().equals(propertiesElement.getName())) {
        return rt;
      }

      if (event.isStartElement()
          && event.asStartElement().getName().getNamespaceURI().equals(NS_DATASERVICES)) {

        String name = event.asStartElement().getName().getLocalPart();
        Attribute2 typeAttribute = event.asStartElement().getAttributeByName(M_TYPE);
        Attribute2 nullAttribute = event.asStartElement().getAttributeByName(M_NULL);
        boolean isNull = nullAttribute != null && "true".equals(nullAttribute.getValue());

        OProperty<?> op = null;

        String type = null;
        boolean isComplexType = false;
        if (typeAttribute != null) {
          type = typeAttribute.getValue();
          EdmType et = EdmType.get(type);
          isComplexType = !et.isSimple();
        }

        if (isComplexType) {
          op =
              OProperties.complex(
                  name,
                  type,
                  isNull
                      ? null
                      : Enumerable.create(parseProperties(reader, event.asStartElement()))
                          .toList());
        } else {
          op = OProperties.parse(name, type, isNull ? null : reader.getElementText());
        }
        rt.add(op);
      }
    }

    throw new RuntimeException();
  }
  private static String innerText(XMLEventReader2 reader, StartElement2 element) {
    StringWriter sw = new StringWriter();
    XMLEventWriter2 writer =
        XMLFactoryProvider2.getInstance().newXMLOutputFactory2().createXMLEventWriter(sw);
    while (reader.hasNext()) {

      XMLEvent2 event = reader.nextEvent();
      if (event.isEndElement() && event.asEndElement().getName().equals(element.getName())) {

        return sw.toString();
      } else {
        writer.add(event);
      }
    }
    throw new RuntimeException();
  }
  private AtomLink parseAtomLink(XMLEventReader2 reader, StartElement2 linkElement) {
    AtomLink rt = new AtomLink();
    rt.relation = getAttributeValueIfExists(linkElement, "rel");
    rt.type = getAttributeValueIfExists(linkElement, "type");
    rt.title = getAttributeValueIfExists(linkElement, "title");
    rt.href = getAttributeValueIfExists(linkElement, "href");

    while (reader.hasNext()) {
      XMLEvent2 event = reader.nextEvent();

      if (event.isEndElement() && event.asEndElement().getName().equals(linkElement.getName())) {
        break;
      } else if (isStartElement(event, ATOM_FEED)) {
        rt.inlineFeed = parseFeed(reader);
      } else if (isStartElement(event, ATOM_ENTRY)) {
        rt.inlineEntry = parseEntry(reader, event.asStartElement());
      }
    }
    return rt;
  }
  private AtomEntry parseEntry(XMLEventReader2 reader, StartElement2 entryElement) {

    String id = null;
    String categoryTerm = null;
    String categoryScheme = null;
    String title = null;
    String summary = null;
    String updated = null;
    String contentType = null;
    List<AtomLink> atomLinks = new ArrayList<AtomLink>();

    String etag = getAttributeValueIfExists(entryElement, M_ETAG);

    AtomEntry rt = null;

    while (reader.hasNext()) {
      XMLEvent2 event = reader.nextEvent();

      if (event.isEndElement() && event.asEndElement().getName().equals(entryElement.getName())) {
        rt.id = id; // http://localhost:8810/Oneoff01.svc/Comment(1)
        rt.title = title;
        rt.summary = summary;
        rt.updated = updated;
        rt.categoryScheme =
            categoryScheme; // http://schemas.microsoft.com/ado/2007/08/dataservices/scheme
        rt.categoryTerm = categoryTerm; // NorthwindModel.Customer
        rt.contentType = contentType;
        rt.atomLinks = atomLinks;

        if (rt instanceof DataServicesAtomEntry) {
          DataServicesAtomEntry dsae = (DataServicesAtomEntry) rt;
          String entitySetName = this.entitySetName;
          if (rt.id != null && rt.id.endsWith(")")) entitySetName = parseEntitySetName(rt.id);
          EdmEntitySet ees = metadata.findEdmEntitySet(entitySetName);
          if (ees == null) {
            // panic! could not determine the entity-set, is it a function?
            EdmFunctionImport efi = metadata.findEdmFunctionImport(entitySetName);
            if (efi != null) ees = efi.entitySet;
          }
          if (ees == null)
            throw new RuntimeException("Could not derive the entity-set for entry: " + rt.id);
          dsae.setOEntity(entityFromAtomEntry(metadata, ees, dsae, fcMapping));
        }
        return rt;
      }

      if (isStartElement(event, ATOM_ID)) {
        id = reader.getElementText();
      } else if (isStartElement(event, ATOM_TITLE)) {
        title = reader.getElementText();
      } else if (isStartElement(event, ATOM_SUMMARY)) {
        summary = reader.getElementText();
      } else if (isStartElement(event, ATOM_UPDATED)) {
        updated = reader.getElementText();
      } else if (isStartElement(event, ATOM_CATEGORY)) {
        categoryTerm = getAttributeValueIfExists(event.asStartElement(), "term");
        categoryScheme = getAttributeValueIfExists(event.asStartElement(), "scheme");

      } else if (isStartElement(event, ATOM_LINK)) {
        AtomLink link = parseAtomLink(reader, event.asStartElement());
        atomLinks.add(link);
      } else if (isStartElement(event, M_PROPERTIES)) {
        rt = parseDSAtomEntry(etag, reader, event);
      } else if (isStartElement(event, ATOM_CONTENT)) {
        contentType = getAttributeValueIfExists(event.asStartElement(), "type");

        if (contentType.equals(MediaType.APPLICATION_XML)) {

          StartElement2 contentElement = event.asStartElement();
          StartElement2 valueElement = null;
          while (reader.hasNext()) {

            XMLEvent2 event2 = reader.nextEvent();

            if (valueElement == null && event2.isStartElement()) {
              valueElement = event2.asStartElement();

              if (isStartElement(event2, M_PROPERTIES)) {
                rt = parseDSAtomEntry(etag, reader, event2);
              } else {
                BasicAtomEntry bae = new BasicAtomEntry();
                bae.content = innerText(reader, event2.asStartElement());
                rt = bae;
              }
            }
            if (event2.isEndElement()
                && event2.asEndElement().getName().equals(contentElement.getName())) {

              break;
            }
          }

        } else {
          BasicAtomEntry bae = new BasicAtomEntry();
          bae.content = innerText(reader, event.asStartElement());
          rt = bae;
        }
      }
    }

    throw new RuntimeException();
  }