8
votes

Meilleur moyen d'analyser xml

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 :


0
votes

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 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.

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 >

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);
    }
  }
}


0 commentaires

-1
votes
    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]);
    }
}
}

1 commentaires

L'OP a dit spécifiquement qu'ils n'ont pas vouloir utiliser DOM (ou tout autre modèle impliquant l'analyse de l'ensemble du document dans une structure d'arborescence en mémoire)



6
votes

Si vous contrôlez la définition du XML, vous pouvez utiliser un outil de liaison XML, par exemple JAXB (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.

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 .

Page JAXB de Oracle


0 commentaires

0
votes

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.

Lorsqu'une chaîne représente un objet en XML, vous pouvez simplement écrire:

commande Theadorder = (commande) xstream.fromxml (xmlstring);

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.


0 commentaires

0
votes

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.


0 commentaires

5
votes

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());
    }
}


0 commentaires

0
votes

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.

http: // MarketMovers.Blogspot.com/2014/02/Le-easy-way-a-read-xml-in-java.html


0 commentaires

0
votes

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");
    }
}


0 commentaires

0
votes

solution sans utiliser d'emballage extérieur, ni même xPath: strong> Utilisez un Enum code> "parse_mode", probablement en combinaison avec un pile code> :

1) la solution de base: strong> p>

a) champs p> xxx pré>

b) faites votre Liste code>, peut-être dans le constructeur: p> xxx pré>

c) 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;
}


0 commentaires