Package dk.brics.xact.operations

Source Code of dk.brics.xact.operations.XMLGraphConverter$PendingNode

package dk.brics.xact.operations;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;

import dk.brics.automaton.Automaton;
import dk.brics.misc.Origin;
import dk.brics.xact.Attribute;
import dk.brics.xact.AttributeGap;
import dk.brics.xact.Comment;
import dk.brics.xact.Element;
import dk.brics.xact.NamespaceDecl;
import dk.brics.xact.Node;
import dk.brics.xact.NodeVisitor;
import dk.brics.xact.ProcessingInstruction;
import dk.brics.xact.TemplateGap;
import dk.brics.xact.Text;
import dk.brics.xact.XML;
import dk.brics.xact.XMLException;
import dk.brics.xmlgraph.AttributeNode;
import dk.brics.xmlgraph.ChoiceNode;
import dk.brics.xmlgraph.ElementNode;
import dk.brics.xmlgraph.SequenceNode;
import dk.brics.xmlgraph.TextNode;
import dk.brics.xmlgraph.XMLGraph;
import dk.brics.xmlgraph.XMLGraphFragment;

/**
* Converter from XML templates to XML graphs.
*/
public class XMLGraphConverter {
 
  private XMLGraphConverter() {}

  /**
   * Gap conversion flags.
   */
  public enum GapConversion {
    /**
     * Ignore gap nodes.
     */
    IGNORE,
   
    /**
     * Leave gaps open.
     */
    OPEN,
   
    /**
     * Close gaps.
     */
    CLOSED,
  }
 
  /**
   * Converts the given XML template into a new XML graph.
   * @param gaps if set, gaps are included, otherwise they are implicitly closed
   * @param wrapchoices if set, extra choice nodes are added around attribute nodes and
   *       element nodes and above text nodes
   */
  public static XMLGraph convert(XML x, GapConversion gaps, boolean wrapchoices) {
    XMLGraph xg = new XMLGraph();
    xg.useFragment(extend(xg, x, gaps, wrapchoices));
    return xg;
  }
 
  private static final class PendingNode {
    public Node node;
    public SequenceNode parent;
    public PendingNode(Node node, SequenceNode parent) {
      this.node = node;
      this.parent = parent;
    }
  }
 
  /**
   * Converts the given XML template by extending an existing XML graph.
   * @param gaps if set, gaps are included, otherwise they are implicitly closed
   */
  public static XMLGraphFragment extend(
          final XMLGraph xg,
          XML x,
          final GapConversion gaps,
          final boolean wrapchoices) {
    final Collection<String> tgaps = new ArrayList<String>();
    final Collection<String> agaps = new ArrayList<String>();
    final Map<String,String> gap_types = new HashMap<String,String>();
    final Map<Element,List<Integer>> contents = new HashMap<Element,List<Integer>>();
    final Stack<PendingNode> pending = new Stack<PendingNode>();
    List<Integer> top_contents = new ArrayList<Integer>();
    SequenceNode top = new SequenceNode(top_contents, x.getOrigin());
    xg.addNode(top);
    pending.add(new PendingNode(x, top));
    while (!pending.isEmpty()) {
      final PendingNode m = pending.pop();
      m.node.visitBy(new NodeVisitor() {

        private void push(Node n, SequenceNode parent) {
          if (n != null)
            pending.push(new PendingNode(n, parent));
        }

        private dk.brics.xmlgraph.Node wrapChoice(dk.brics.xmlgraph.Node n) {
          if (!(n instanceof ChoiceNode)) {
            Collection<Integer> cs = new ArrayList<Integer>();
            cs.add(n.getIndex());
            n = new ChoiceNode(cs, n.getOrigin());
            xg.addNode(n);
          }
          return n;
       
       
        @Override
        public void visit(Text n) {
          dk.brics.xmlgraph.Node tn = new TextNode(Automaton.makeString(n.getString()), n.getOrigin());
          xg.addNode(tn);
          if (wrapchoices)
            tn = wrapChoice(tn);
          m.parent.addContent(tn.getIndex());
          push(n.getNextSibling(), m.parent);
        }
       
        @Override
        public void visit(Element n) {
          List<Integer> cs = new ArrayList<Integer>();
          contents.put(n, cs); // contents added later
          SequenceNode content = new SequenceNode(cs, n.getOrigin());
          xg.addNode(content);
          dk.brics.xmlgraph.Node sn = content;
          if (wrapchoices)
            sn = wrapChoice(sn);
          dk.brics.xmlgraph.Node en = new ElementNode(Automaton.makeString(n.getExpandedName()),
              sn.getIndex(), false, n.getOrigin());
          xg.addNode(en);
          if (wrapchoices)
            en = wrapChoice(en);
          m.parent.addContent(en.getIndex());
          push(n.getNextSibling(), m.parent);
          push(n.getFirstAttr(), content);
          push(n.getFirstChild(), content);
        }

        @Override
        public void visit(TemplateGap n) {
          if (gaps != GapConversion.IGNORE) {
            dk.brics.xmlgraph.Node cn = new ChoiceNode(n.getGap(), gaps == GapConversion.OPEN, false, Collections.<Integer>emptyList(), n.getOrigin());
            xg.addNode(cn);
            m.parent.addContent(cn.getIndex());
            tgaps.add(n.getGap());
            addGapType(n.getGap(), n.getType(), n.getOrigin());
          }
          push(n.getNextSibling(), m.parent);
        }
       
        @Override
        public void visit(Attribute n) {
          dk.brics.xmlgraph.Node vn = new TextNode(Automaton.makeString(n.getValue()), n.getOrigin());
          xg.addNode(vn);
          if (wrapchoices)
            vn = wrapChoice(vn);
          dk.brics.xmlgraph.Node an = new AttributeNode(Automaton.makeString(n.getExpandedName()),
              vn.getIndex(), n.getOrigin());
          xg.addNode(an);
          if (wrapchoices)
            an = wrapChoice(an);
          m.parent.addContent(an.getIndex());
          push(n.getNextAttr(), m.parent);
        }
       
        @Override
        public void visit(AttributeGap n) {
          if (gaps != GapConversion.IGNORE) {
            dk.brics.xmlgraph.Node cn = new ChoiceNode(n.getGap(), gaps == GapConversion.OPEN, false, Collections.<Integer>emptyList(), n.getOrigin());
            xg.addNode(cn);
            dk.brics.xmlgraph.Node an = new AttributeNode(Automaton.makeString(n.getExpandedName()),
                cn.getIndex(), n.getOrigin());
            xg.addNode(an);
            if (wrapchoices)
              an = wrapChoice(an);
            m.parent.addContent(an.getIndex());
            agaps.add(n.getGap());
            addGapType(n.getGap(), n.getType(), n.getOrigin());
          }
          push(n.getNextAttr(), m.parent);
        }
       
        @Override
        public void visit(ProcessingInstruction n) {
          push(n.getNextSibling(), m.parent);
        }
       
        @Override
        public void visit(Comment n) {
          push(n.getNextSibling(), m.parent);
        }
       
        @Override
        public void visit(NamespaceDecl n) {
        }

        private void addGapType(String gap, String type, Origin origin) {
          if (type != null) {
            String t = gap_types.get(gap);
            if (t == null)
              gap_types.put(gap, type);
            else if (!t.equals(type))
              throw new XMLException("type mismatch for gap " + gap, origin);
          }
        }
      });
    }
    return new XMLGraphFragment(top, tgaps, agaps, gap_types);
  }
}
TOP

Related Classes of dk.brics.xact.operations.XMLGraphConverter$PendingNode

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.