protected List<Object> readArray(XMLStreamReader parser) throws XMLStreamException { if (XMLStreamConstants.START_ELEMENT != parser.getEventType()) { throw new RuntimeException("must be start element, not: " + parser.getEventType()); } if (!"arr".equals(parser.getLocalName().toLowerCase(Locale.ENGLISH))) { throw new RuntimeException("must be 'arr', not: " + parser.getLocalName()); } StringBuilder builder = new StringBuilder(); KnownType type = null; List<Object> vals = new ArrayList<Object>(); int depth = 0; while (true) { switch (parser.next()) { case XMLStreamConstants.START_ELEMENT: depth++; KnownType t = KnownType.get(parser.getLocalName()); if (t == null) { throw new RuntimeException("this must be known type! not: " + parser.getLocalName()); } if (type == null) { type = t; } /** * * actually, there is no rule that arrays need the same type else if( type != t && !(t * == KnownType.NULL || type == KnownType.NULL)) { throw new RuntimeException( "arrays * must have the same type! ("+type+"!="+t+") "+parser.getLocalName() ); } * */ type = t; builder.setLength(0); // reset the text if (!type.isLeaf) { switch (type) { case LST: vals.add(readNamedList(parser)); depth--; continue; case ARR: vals.add(readArray(parser)); depth--; continue; case RESULT: vals.add(readDocuments(parser)); depth--; continue; case DOC: vals.add(readDocument(parser)); depth--; continue; } throw new XMLStreamException("branch element not handled!", parser.getLocation()); } break; case XMLStreamConstants.END_ELEMENT: if (--depth < 0) { return vals; // the last element is itself } // System.out.println( "ARR:"+type+"::"+builder ); Object val = type.read(builder.toString().trim()); if (val == null && type != KnownType.NULL) { throw new XMLStreamException("error reading value:" + type, parser.getLocation()); } vals.add(val); break; case XMLStreamConstants .SPACE: // TODO? should this be trimmed? make sure it only gets one/two space? case XMLStreamConstants.CDATA: case XMLStreamConstants.CHARACTERS: builder.append(parser.getText()); break; } } }
protected SolrDocument readDocument(XMLStreamReader parser) throws XMLStreamException { if (XMLStreamConstants.START_ELEMENT != parser.getEventType()) { throw new RuntimeException("must be start element, not: " + parser.getEventType()); } if (!"doc".equals(parser.getLocalName().toLowerCase(Locale.ENGLISH))) { throw new RuntimeException("must be 'lst', not: " + parser.getLocalName()); } SolrDocument doc = new SolrDocument(); StringBuilder builder = new StringBuilder(); KnownType type = null; String name = null; // just eat up the events... int depth = 0; while (true) { switch (parser.next()) { case XMLStreamConstants.START_ELEMENT: depth++; builder.setLength(0); // reset the text type = KnownType.get(parser.getLocalName()); if (type == null) { throw new RuntimeException("this must be known type! not: " + parser.getLocalName()); } name = null; int cnt = parser.getAttributeCount(); for (int i = 0; i < cnt; i++) { if ("name".equals(parser.getAttributeLocalName(i))) { name = parser.getAttributeValue(i); break; } } if (name == null) { throw new XMLStreamException( "requires 'name' attribute: " + parser.getLocalName(), parser.getLocation()); } // Handle multi-valued fields if (type == KnownType.ARR) { for (Object val : readArray(parser)) { doc.addField(name, val); } depth--; // the array reading clears out the 'endElement' } else if (!type.isLeaf) { throw new XMLStreamException("must be value or array", parser.getLocation()); } break; case XMLStreamConstants.END_ELEMENT: if (--depth < 0) { return doc; } // System.out.println( "FIELD:"+type+"::"+name+"::"+builder ); Object val = type.read(builder.toString().trim()); if (val == null) { throw new XMLStreamException("error reading value:" + type, parser.getLocation()); } doc.addField(name, val); break; case XMLStreamConstants .SPACE: // TODO? should this be trimmed? make sure it only gets one/two space? case XMLStreamConstants.CDATA: case XMLStreamConstants.CHARACTERS: builder.append(parser.getText()); break; } } }
protected NamedList<Object> readNamedList(XMLStreamReader parser) throws XMLStreamException { if (XMLStreamConstants.START_ELEMENT != parser.getEventType()) { throw new RuntimeException("must be start element, not: " + parser.getEventType()); } StringBuilder builder = new StringBuilder(); NamedList<Object> nl = new SimpleOrderedMap<Object>(); KnownType type = null; String name = null; // just eat up the events... int depth = 0; while (true) { switch (parser.next()) { case XMLStreamConstants.START_ELEMENT: depth++; builder.setLength(0); // reset the text type = KnownType.get(parser.getLocalName()); if (type == null) { throw new RuntimeException("this must be known type! not: " + parser.getLocalName()); } name = null; int cnt = parser.getAttributeCount(); for (int i = 0; i < cnt; i++) { if ("name".equals(parser.getAttributeLocalName(i))) { name = parser.getAttributeValue(i); break; } } /** * The name in a NamedList can actually be null if( name == null ) { throw new * XMLStreamException( "requires 'name' attribute: "+parser.getLocalName(), * parser.getLocation() ); } */ if (!type.isLeaf) { switch (type) { case LST: nl.add(name, readNamedList(parser)); depth--; continue; case ARR: nl.add(name, readArray(parser)); depth--; continue; case RESULT: nl.add(name, readDocuments(parser)); depth--; continue; case DOC: nl.add(name, readDocument(parser)); depth--; continue; } throw new XMLStreamException("branch element not handled!", parser.getLocation()); } break; case XMLStreamConstants.END_ELEMENT: if (--depth < 0) { return nl; } // System.out.println( "NL:ELEM:"+type+"::"+name+"::"+builder ); nl.add(name, type.read(builder.toString().trim())); break; case XMLStreamConstants .SPACE: // TODO? should this be trimmed? make sure it only gets one/two space? case XMLStreamConstants.CDATA: case XMLStreamConstants.CHARACTERS: builder.append(parser.getText()); break; } } }