J'ai analysé XML comme celui-ci depuis des années et je dois admettre que le nombre d'éléments différents devient plus important, je le trouve un peu ennuyeux et épuisant à faire, voici ce que je veux dire, échantillon mannequin XML:
public class SaxParser extends DefaultHandler { boolean isItem = false; boolean isOrder = false; boolean isDate = false; boolean isCustomerId = false; private Order order; private Item item; @Override public void startElement(String namespaceURI, String localName, String qName, Attributes atts) { if (localName.equalsIgnoreCase("ORDER")) { order = new Order(); } if (localName.equalsIgnoreCase("DATE")) { isDate = true; } if (localName.equalsIgnoreCase("CUSTOMERID")) { isCustomerId = true; } if (localName.equalsIgnoreCase("ITEM")) { isItem = true; } } public void characters(char ch[], int start, int length) throws SAXException { if (isDate){ SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd"); String value = new String(ch, start, length); try { order.setDate(formatter.parse(value)); } catch (ParseException e) { e.printStackTrace(); } } if(isCustomerId){ order.setCustomerId(Integer.valueOf(new String(ch, start, length))); } if (isItem) { item = new Item(); isItem = false; } } }
9 Réponses :
en SAX L'analyseur "pousse" les événements de votre gestionnaire, vous devez donc faire tout le ménage comme vous l'habituez ici. Une alternative serait Stax (le Selon la structure précise du XML, il peut y avoir une "voie moyenne" Utilisation d'une boîte à outils comme XOM , qui a un mode de fonctionnement dans lequel vous analyser un sous-arbre du document dans un modèle d'objet de type DOM , Processez ce brindille, puis jetez-le et analysez le suivant. C'est bon pour les documents répétitifs avec de nombreux éléments similaires qui peuvent chacun être traitées isolément - vous obtenez la facilité de programmation dans une API basée sur des arbres au sein de chaque brindille, mais vous avez toujours le comportement en streaming qui vous permet d'analyser efficacement les documents énormes. P > javax.xml.stream code> package), qui est toujours en streaming, mais votre code est responsable des événements "tirant" de l'analyseur. De cette façon, la logique de quels éléments sont attendus dans quel ordre est codé dans le flux de contrôle de votre programme plutôt que de devoir être explicitement représenté dans des booléens.
public class ItemProcessor extends NodeFactory {
private Nodes emptyNodes = new Nodes();
public Nodes finishMakingElement(Element elt) {
if("Item".equals(elt.getLocalName())) {
// process the Item element here
System.out.println(elt.getFirstChildElement("ItemId").getValue()
+ ": " + elt.getFirstChildElement("ItemName").getValue());
// then throw it away
return emptyNodes;
} else {
return super.finishMakingElement(elt);
}
}
}
import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathFactory; import org.w3c.dom.Document; import org.w3c.dom.NodeList; public class JXML { private DocumentBuilder builder; private Document doc = null; private DocumentBuilderFactory factory ; private XPathExpression expr = null; private XPathFactory xFactory; private XPath xpath; private String xmlFile; public static ArrayList<String> XMLVALUE ; public JXML(String xmlFile){ this.xmlFile = xmlFile; } private void xmlFileSettings(){ try { factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); xFactory = XPathFactory.newInstance(); xpath = xFactory.newXPath(); builder = factory.newDocumentBuilder(); doc = builder.parse(xmlFile); } catch (Exception e){ System.out.println(e); } } public String[] selectQuery(String query){ xmlFileSettings(); ArrayList<String> records = new ArrayList<String>(); try { expr = xpath.compile(query); Object result = expr.evaluate(doc, XPathConstants.NODESET); NodeList nodes = (NodeList) result; for (int i=0; i<nodes.getLength();i++){ records.add(nodes.item(i).getNodeValue()); } return records.toArray(new String[records.size()]); } catch (Exception e) { System.out.println("There is error in query string"); return records.toArray(new String[records.size()]); } } public boolean updateQuery(String query,String value){ xmlFileSettings(); try{ NodeList nodes = (NodeList) xpath.evaluate(query, doc, XPathConstants.NODESET); for (int idx = 0; idx < nodes.getLength(); idx++) { nodes.item(idx).setTextContent(value); } Transformer xformer = TransformerFactory.newInstance().newTransformer(); xformer.transform(new DOMSource(doc), new StreamResult(new File(this.xmlFile))); return true; }catch(Exception e){ System.out.println(e); return false; } } public static void main(String args[]){ JXML jxml = new JXML("c://user.xml"); jxml.updateQuery("//Order/CustomerId/text()","222"); String result[]=jxml.selectQuery("//Order/Item/*/text()"); for(int i=0;i<result.length;i++){ System.out.println(result[i]); } } }
L'OP a dit spécifiquement qu'ils i> n'ont pas i> vouloir utiliser DOM (ou tout autre modèle impliquant l'analyse de l'ensemble du document dans une structure d'arborescence en mémoire)
Si vous contrôlez la définition du XML, vous pouvez utiliser un outil de liaison XML, par exemple JAXB STRORT> (architecture Java pour la liaison XML.) Dans JAXB, vous pouvez définir un schéma pour la structure XML ( XSD et d'autres sont pris en charge) ou annotez vos classes Java afin de définir les règles de sérialisation. Une fois que vous avez une cartographie déclarative claire entre XML et Java, la marshalling et la déshabillage de XML devient triviale. P>
Utiliser JAXB nécessite plus de mémoire que les gestionnaires de saxo, mais il existe des méthodes pour traiter les documents XML par parties: Documents . P>
J'utilise Xsteam pour sérialiser mes propres objets à XML, puis les charger comme des objets Java . Si vous pouvez représenter tout ce qui concerne les pojos et vous annotant correctement les pojos pour correspondre aux types de votre fichier XML, vous pourriez trouver qu'il est plus facile d'utiliser. P>
Lorsqu'une chaîne représente un objet en XML, vous pouvez simplement écrire: p>
Je l'ai toujours utilisé pour charger un objet en mémoire dans une seule ligne, mais si vous devez le diffuser et le processus, vous devriez pouvoir utiliser un hierarchicalstreamreader à itérer le document. Cela pourrait être très similaire à simple, suggéré par @Dave. P> commande Theadorder = (commande) xstream.fromxml (xmlstring); code> p>
Comme d'autres suggéraient, un modèle Stax serait une meilleure approche pour minimiser l'impression de pied de mémoire car il s'agit d'un modèle à base de poussée. J'ai utilisé personnellement axio (qui est utilisé dans APache Axis) et d'analyser les éléments à l'aide des expressions XPath moins verbose que de traverser des éléments de nœud que vous avez effectué dans l'extrait de code fourni. P>
Voici un exemple d'utilisation de Jaxb avec Stax.
Document d'entrée: P>
public class PersonlistProcessor { public static void main(String[] args) throws Exception { new PersonlistProcessor().processPersonlist(PersonlistProcessor.class .getResourceAsStream("personlist.xml")); } // TODO: Instead of throws Exception, all exceptions should be wrapped // inside runtime exception public void processPersonlist(InputStream inputStream) throws Exception { JAXBContext jaxbContext = JAXBContext.newInstance(Person.class); XMLStreamReader xss = XMLInputFactory.newFactory().createXMLStreamReader(inputStream); // Create unmarshaller Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); // Go to next tag xss.nextTag(); // Require Personlist xss.require(XMLStreamReader.START_ELEMENT, "http://example.org", "Personlist"); // Go to next tag while (xss.nextTag() == XMLStreamReader.START_ELEMENT) { // Require Person xss.require(XMLStreamReader.START_ELEMENT, "http://example.org", "Person"); // Unmarshall person Person person = (Person)unmarshaller.unmarshal(xss); // Process person processPerson(person); } // Require Personlist xss.require(XMLStreamReader.END_ELEMENT, "http://example.org", "Personlist"); } private void processPerson(Person person) { System.out.println(person.getName()); System.out.println(person.getAddress().getCountryName()); } }
J'utilise cette bibliothèque. Il est assis sur la bibliothèque Java standard et vous facilite la tâche. En particulier, vous pouvez demander un élément ou un attribut spécifique par nom, plutôt que d'utiliser la grande instruction "si" que vous avez décrite. P>
http: // MarketMovers.Blogspot.com/2014/02/Le-easy-way-a-read-xml-in-java.html P>
Il existe une autre bibliothèque qui prend en charge une analyse XML plus compacte, RTXML. La bibliothèque et sa documentation sont sur rasmustorkel.com . J'ai mis en œuvre la analyse du fichier dans la question initiale et je comprendais le programme complet ici:
package for_so; import java.io.File; import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; import rasmus_torkel.xml_basic.read.TagNode; import rasmus_torkel.xml_basic.read.XmlReadOptions; import rasmus_torkel.xml_basic.read.impl.XmlReader; public class Q15626686_ReadOrder { public static class Order { public final Date _date; public final int _customerId; public final String _customerName; public final ArrayList<Item> _itemAl; public Order(TagNode node) { _date = (Date)node.nextStringMappedFieldE("Date", Date.class); _customerId = (int)node.nextIntFieldE("CustomerId"); _customerName = node.nextTextFieldE("CustomerName"); _itemAl = new ArrayList<Item>(); boolean finished = false; while (!finished) { TagNode itemNode = node.nextChildN("Item"); if (itemNode != null) { Item item = new Item(itemNode); _itemAl.add(item); } else { finished = true; } } node.verifyNoMoreChildren(); } } public static final Pattern DATE_PATTERN = Pattern.compile("^(\\d\\d\\d\\d)\\/(\\d\\d)\\/(\\d\\d)$"); public static class Date { public final String _dateString; public final int _year; public final int _month; public final int _day; public Date(String dateString) { _dateString = dateString; Matcher matcher = DATE_PATTERN.matcher(dateString); if (!matcher.matches()) { throw new RuntimeException(dateString + " does not match pattern " + DATE_PATTERN.pattern()); } _year = Integer.parseInt(matcher.group(1)); _month = Integer.parseInt(matcher.group(2)); _day = Integer.parseInt(matcher.group(3)); } } public static class Item { public final int _itemId; public final String _itemName; public final Quantity _quantity; public Item(TagNode node) { _itemId = node.nextIntFieldE("ItemId"); _itemName = node.nextTextFieldE("ItemName"); _quantity = new Quantity(node.nextChildE("Quantity")); node.verifyNoMoreChildren(); } } public static class Quantity { public final int _unitSize; public final int _unitQuantity; public Quantity(TagNode node) { _unitSize = node.attributeIntD("unit", 1); _unitQuantity = node.onlyInt(); } } public static void main(String[] args) { File xmlFile = new File(args[0]); TagNode orderNode = XmlReader.xmlFileToRoot(xmlFile, "Order", XmlReadOptions.DEFAULT); Order order = new Order(orderNode); System.out.println("Read order for " + order._customerName + " which has " + order._itemAl.size() + " items"); } }
a) champs p> b) faites votre Liste c) Enum code> "parse_mode", probablement en combinaison avec un
pile
startelement code> et
endelement code> : P>
private enum PARSE_MODE implements SAXHandlerParseMode {
ORDER, DATE, CUSTOMERID, ITEM
};
private Collection<Enum<?>> possibleModes;
@Override
protected Collection<Enum<?>> getPossibleModes() {
// lazy initiation
if (possibleModes == null) {
List<SAXHandlerParseMode> parseModes = new ArrayList<SAXHandlerParseMode>( Arrays.asList(PARSE_MODE.values()) );
possibleModes = new ArrayList<Enum<?>>();
for( SAXHandlerParseMode parseMode : parseModes ){
possibleModes.add( PARSE_MODE.valueOf( parseMode.toString() ));
}
// __UNDEFINED__ mode (from abstract superclass) must be added afterwards
possibleModes.add( AbstractSAXHandler.PARSE_MODE.__UNDEFINED__ );
}
return possibleModes;
}
Si vous avez un modèle de données de concert qui génère le XML, je jetterais un coup d'oeil à Xstream ( xstream.codehaus.org a>). Il fait un très bon travail de données sérialisées dans XML et en arrière.
Sur le sujet, j'aime commencer par Xsds et utiliser Xmlbeans. Légèrement OT, les balises XML sont censées être sensibles à la casse et ce code rompt cela.