扫描 xml文件所在的文件位置 并识别配置加载到内存缓存中.
@param xmlLocations zealot的XML文件所在的位置
@return ZealotConfigManager的全局唯一实例
542984
public ZealotConfigManager initLoadXmlLocations(String xmlLocations) {
        this.xmlLocations = StringHelper.isBlank(xmlLocations) ? "zealot" : xmlLocations;
        XmlScanner.newInstance().scan(this.xmlLocations);
        this.cachingXmlAndEval();
        return this;
    }
214374
public function getLocationNodeTypes() {
    $fieldMap = $this->entityFieldManager->getFieldMap();
    $locationBundles = $fieldMap['node']['field_location_coordinates']['bundles'];
    $nodeTypes = $this->entityTypeManager->getStorage('node_type')->loadByProperties(['type' => array_keys($locationBundles)]);

    return $nodeTypes;
  }
470892
public void initLoad(Class<? extends AbstractZealotConfig> clazz, String xmlLocations,
            String handlerLocations) {
        this.initLoad(clazz.getName(), xmlLocations, handlerLocations);
    }
790423
private void loadZealotConfig(AbstractZealotConfig zealotConfig) {
        zealotConfig.configNormal(NormalConfig.getInstance());
        zealotConfig.configXml(XmlContext.INSTANCE);
        zealotConfig.configTagHandler();
        log.warn("Zealot的配置信息加载完成!");
    }
123091
@XmlElementDecl(namespace = "http://www.w3.org/1999/xlink", name = "locator")
    public JAXBElement<LocatorType> createLocator(LocatorType value) {
        return new JAXBElement<LocatorType>(_Locator_QNAME, LocatorType.class, null, value);
    }
855778
public static Location getLocation(Attributes attrs, String description) {
		String src = attrs.getValue(URI, SRC_ATTR);
		if (src == null) {
			return LocationImpl.UNKNOWN;
		}
		return new LocationImpl(description, src, getLine(attrs), getColumn(attrs));
	}
976938
@SuppressWarnings("unchecked")
    public static List<Node> selectNodes(Node node, String xpathQuery, Map<String, String> namespaceUris) {
        XPath xpath = DocumentHelper.createXPath(xpathQuery);
        xpath.setNamespaceURIs(namespaceUris);

        return xpath.selectNodes(node);
    }
896208
@SuppressWarnings("unchecked")
    private void buildDocument(Element parent, Object pojo, Class<?> clazz, boolean ignoreNull) {
        //字段描述，key是节点名，value是XmlData
        Map<String, XmlData> map = new HashMap<>();
        //构建字段描述
        if (pojo instanceof Map) {
            Map<?, ?> pojoMap = (Map<?, ?>) pojo;
            pojoMap.forEach((k, v) -> {
                if (k == null) {
                    log.debug("忽略map中key为null的值");
                } else {
                    if (ignoreNull && v == null) {
                        log.debug("当前配置为忽略空值，[{}]的值为空，忽略", k);
                    } else {
                        map.put(String.valueOf(k),
                            new XmlData(null, v, v == null ? null : v.getClass()));
                    }
                }
            });
        } else {
            CustomPropertyDescriptor[] propertyDescriptors = BeanUtils
                .getPropertyDescriptors(clazz == null ? pojo.getClass() : clazz);
            for (CustomPropertyDescriptor descriptor : propertyDescriptors) {
                XmlNode xmlNode = descriptor.getAnnotation(XmlNode.class);
                //字段值
                try {
                    Object valueObj = pojo == null ? null
                        : BeanUtils.getProperty(pojo, descriptor.getName());
                    //判断是否忽略
                    if ((ignoreNull && valueObj == null) || (xmlNode != null && xmlNode.ignore())) {
                        log.debug("忽略空节点或者节点被注解忽略");
                        continue;
                    }

                    //节点名
                    String nodeName = (xmlNode == null || StringUtils.isEmpty(xmlNode.name()))
                        ? descriptor.getName()
                        : xmlNode.name();
                    map.put(nodeName, new XmlData(xmlNode, valueObj, descriptor.getRealType()));
                } catch (Exception e) {
                    log.error("获取字段值时发生异常，忽略改值", e);
                }
            }
        }

        map.forEach((k, v) -> {
            XmlNode xmlNode = v.getXmlNode();
            Object valueObj = v.getData();

            //节点名
            String nodeName = k;
            //属性名
            String attrName = (xmlNode == null || StringUtils.isEmpty(xmlNode.attributeName()))
                ? nodeName
                : xmlNode.attributeName();
            //是否是cdata
            boolean isCDATA = xmlNode != null && xmlNode.isCDATA();
            //数据类型
            Class<?> type = v.getType();
            //构建一个对应的节点
            Element node = parent.element(nodeName);
            if (node == null) {
                //搜索不到，创建一个（在属性是父节点属性的情况和节点是list的情况需要将该节点删除）
                node = DocumentHelper.createElement(nodeName);
                parent.add(node);
            }

            //判断字段对应的是否是属性
            if (xmlNode != null && xmlNode.isAttribute()) {
                //属性值，属性值只能是简单值
                String attrValue = valueObj == null ? "" : String.valueOf(valueObj);
                //判断是否是父节点的属性
                if (StringUtils.isEmpty(xmlNode.name())) {
                    //如果是父节点那么删除之前添加的
                    parent.remove(node);
                    node = parent;
                }
                //为属性对应的节点添加属性
                node.addAttribute(attrName, attrValue);
            } else if (type == null) {
                log.debug("当前不知道节点[{}]的类型，忽略该节点", k);
            } else if (JavaTypeUtil.isNotPojo(type)) {
                //是简单类型或者集合类型
                if (Map.class.isAssignableFrom(type)) {
                    log.warn("当前字段[{}]是map类型", k);
                    buildDocument(node, v.getData(), type, ignoreNull);
                } else if (Collection.class.isAssignableFrom(type)) {
                    parent.remove(node);
                    //集合类型
                    //判断字段值是否为null
                    if (valueObj != null) {
                        String arrayNodeName;
                        Element root;
                        if (StringUtils.isEmpty(xmlNode.arrayRoot())) {
                            arrayNodeName = nodeName;
                            root = parent;
                        } else {
                            arrayNodeName = xmlNode.arrayRoot();
                            root = DocumentHelper.createElement(nodeName);
                            parent.add(root);
                        }
                        Collection collection = (Collection) valueObj;
                        collection.stream().forEach(obj -> {
                            Element n = DocumentHelper.createElement(arrayNodeName);
                            root.add(n);
                            buildDocument(n, obj, null, ignoreNull);
                        });
                    }
                } else {
                    String text = valueObj == null ? "" : String.valueOf(valueObj);
                    if (isCDATA) {
                        log.debug("内容[{}]需要CDATA标签包裹", text);
                        node.add(DocumentHelper.createCDATA(text));
                    } else {
                        node.setText(text);
                    }
                }
            } else {
                //猜测字段类型（防止字段的声明是一个接口，优先采用xmlnode中申明的类型）
                Class<?> realType = resolveRealType(type, xmlNode);
                //pojo类型
                buildDocument(node, valueObj, realType, ignoreNull);
            }
        });
    }
900879
public static JavadocHelper create(JavacTask mainTask, Collection<? extends Path> sourceLocations) {
        StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null);
        try {
            fm.setLocationFromPaths(StandardLocation.SOURCE_PATH, sourceLocations);
            return new OnDemandJavadocHelper(mainTask, fm);
        } catch (IOException ex) {
            try {
                fm.close();
            } catch (IOException closeEx) {
            }
            return new JavadocHelper() {
                @Override
                public String getResolvedDocComment(Element forElement) throws IOException {
                    return null;
                }
                @Override
                public Element getSourceElement(Element forElement) throws IOException {
                    return forElement;
                }
                @Override
                public void close() throws IOException {}
            };
        }
    }
1126120
@NotNull
    public static XPath createXPath(@Nullable final String... values) {
        final NamespaceContext context = new NamespaceContextMap(values);
        final XPath xPath = XPathFactory.newInstance().newXPath();
        xPath.setNamespaceContext(context);
        return xPath;
    }
326627
public Set<String> getCellularLocations()
	{
		Set<String> locs = new HashSet<String>();
		for (PhysicalEntity pe : pes)
		{
			CellularLocationVocabulary voc = pe.getCellularLocation();
			if (voc != null)
			{
				for (String term : voc.getTerm())
				{
					if (term != null && term.length() > 0) locs.add(term);
				}
			}
		}
		return locs;
	}
1027188
function constructPaths(xmlElement) {
  if (xmlElement['path'] == null) {
    return ['*'];
  }

  var paths = [];
  xmlElement.path.some(function(pathElement) {
    var url = pathElement['$']['url'];

    // Ignore explicit paths if '*' is defined
    if (url === '*') {
      paths = ['*'];
      return true;
    }

    paths.push(url);
  });

  return paths;
}
577558
@SuppressWarnings("unchecked")
    private void cachingXmlZealots() {
        Map<String, String> xmlMaps = XmlContext.INSTANCE.getXmlPathMap();

        // 遍历所有的xml文档，将每个zealot节点缓存到ConcurrentHashMap内存缓存中
        for (Map.Entry<String, String> entry: xmlMaps.entrySet()) {
            String nameSpace = entry.getKey();
            String filePath = entry.getValue();

            // 根据文件路径获取对应的dom4j Document对象.
            Document doc = XmlNodeHelper.getDocument(filePath);
            if (doc == null) {
                throw new ConfigNotFoundException("注意：未找到配置文件中xml对应的dom4j Document文档,nameSpace为:" + nameSpace);
            }

            // 获取该文档下所有的zealot元素,
            List<Node> zealotNodes = doc.selectNodes(ZealotConst.ZEALOT_TAG);
            for (Node zealotNode: zealotNodes) {
                String zealotId = XmlNodeHelper.getNodeText(zealotNode.selectSingleNode(ZealotConst.ATTR_ID));
                if (StringHelper.isBlank(zealotId)) {
                    throw new NodeNotFoundException("该xml文件中有zealot节点的zealotId属性为空，请检查！文件为:" + filePath);
                }

                // zealot节点缓存到Map中，key是由nameSpace和zealot id组成,用"@@"符号分隔,value是zealotNode
                String zealotKey = StringHelper.concat(nameSpace, ZealotConst.SP_AT, zealotId);
                AbstractZealotConfig.getZealots().put(zealotKey, zealotNode);
            }
        }
    }
116095
public static <T> List<ConfigurationInfo<T>> newList(boolean isOptional, T location) {
    if (location == null) {
      throw new IllegalArgumentException("location cannot be null");
    }
    return newList(Collections.<T>singletonList(location), isOptional);
  }
422617
public static String constructSerializerInfoXml(StoreDefinition storeDefinition) {
        Element store = new Element(StoreDefinitionsMapper.STORE_ELMT);
        store.addContent(new Element(StoreDefinitionsMapper.STORE_NAME_ELMT).setText(storeDefinition.getName()));
        Element keySerializer = new Element(StoreDefinitionsMapper.STORE_KEY_SERIALIZER_ELMT);
        StoreDefinitionsMapper.addSerializer(keySerializer, storeDefinition.getKeySerializer());
        store.addContent(keySerializer);

        Element valueSerializer = new Element(StoreDefinitionsMapper.STORE_VALUE_SERIALIZER_ELMT);
        StoreDefinitionsMapper.addSerializer(valueSerializer, storeDefinition.getValueSerializer());
        store.addContent(valueSerializer);

        XMLOutputter serializer = new XMLOutputter(Format.getPrettyFormat());
        return serializer.outputString(store);
    }
490247
public static XSLTTransformationFileSystem usingFilesystem(String location)
    {
        XSLTTransformation tansformation = new XSLTTransformation();
        tansformation.template = location;
        return tansformation;
    }
1010232
@Override
  public MtasTokenCollection createTokenCollection(Reader reader)
      throws MtasParserException, MtasConfigException {
    Boolean hasRoot = rootTag == null ? true : false;
    Boolean parsingContent = contentTag == null ? true : false;
    String textContent = null;
    Integer unknownAncestors = 0;
    Integer lastOffset = 0;

    AtomicInteger position = new AtomicInteger(0);
    Map<String, Set<Integer>> idPositions = new HashMap<>();
    Map<String, Integer[]> idOffsets = new HashMap<>();

    Map<String, Map<Integer, Set<String>>> updateList = createUpdateList();
    Map<String, List<MtasParserObject>> currentList = createCurrentList();
    Map<String, Map<String, String>> variables = createVariables();

    tokenCollection = new MtasTokenCollection();
    MtasTokenIdFactory mtasTokenIdFactory = new MtasTokenIdFactory();
    XMLInputFactory factory = XMLInputFactory.newInstance();
    try {      
      XMLStreamReader streamReader = factory.createXMLStreamReader(reader);
      QName qname;
      try {
        int event = streamReader.getEventType();
        MtasParserType<?> currentType;
        MtasParserType<?> tmpCurrentType;
        MtasParserType<?> tmpVariableType;
        MtasParserObject currentObject = null;
        MtasParserObject variableObject = null;
        while (true) {
          switch (event) {
          case XMLStreamConstants.START_DOCUMENT:
            log.debug("start of document");
            String encodingScheme = streamReader.getCharacterEncodingScheme();
            if (encodingScheme == null) {
              //ignore for now
              log.info("No encodingScheme found, assume utf-8");
              //throw new MtasParserException("No encodingScheme found");              
            } else if (!encodingScheme.equalsIgnoreCase("utf-8")) {
              throw new MtasParserException(
                  "XML not UTF-8 encoded but '" + encodingScheme + "'");
            }
            break;
          case XMLStreamConstants.END_DOCUMENT:
            log.debug("end of document");
            break;
          case XMLStreamConstants.SPACE:
            // set offset (end of start-element)
            lastOffset = streamReader.getLocation().getCharacterOffset();
            break;
          case XMLStreamConstants.START_ELEMENT:
            // get data
            qname = streamReader.getName();
            // check for rootTag
            if (!hasRoot) {
              if (qname.equals(getQName(rootTag))) {
                hasRoot = true;
              } else {
                throw new MtasParserException("No " + rootTag);
              }
              // parse content
            } else {
              if ((tmpVariableType = variableTypes.get(qname)) != null) {
                variableObject = new MtasParserObject(tmpVariableType);
                collectAttributes(variableObject, streamReader);
                computeVariablesFromObject(variableObject, currentList,
                    variables);
              }
              if (parsingContent) {
                // check for relation : not within word, not within
                // groupAnnotation
                if ((currentList.get(MAPPING_TYPE_WORD).isEmpty())
                    && (currentList.get(MAPPING_TYPE_GROUP_ANNOTATION)
                        .isEmpty())
                    && (tmpCurrentType = relationTypes.get(qname)) != null) {
                  currentObject = new MtasParserObject(tmpCurrentType);
                  collectAttributes(currentObject, streamReader);
                  currentObject.setUnknownAncestorNumber(unknownAncestors);
                  currentObject.setRealOffsetStart(lastOffset);
                  if (!prevalidateObject(currentObject, currentList)) {
                    unknownAncestors++;
                  } else {
                    currentType = tmpCurrentType;
                    currentList.get(MAPPING_TYPE_RELATION).add(currentObject);
                    unknownAncestors = 0;
                  }
                  // check for relation annotation: not within word, but within
                  // relation
                } else if ((currentList.get(MAPPING_TYPE_WORD).isEmpty())
                    && (!currentList.get(MAPPING_TYPE_RELATION).isEmpty())
                    && (tmpCurrentType = relationAnnotationTypes
                        .get(qname)) != null) {
                  currentObject = new MtasParserObject(tmpCurrentType);
                  collectAttributes(currentObject, streamReader);
                  currentObject.setUnknownAncestorNumber(unknownAncestors);
                  currentObject.setRealOffsetStart(lastOffset);
                  if (!prevalidateObject(currentObject, currentList)) {
                    unknownAncestors++;
                  } else {
                    currentType = tmpCurrentType;
                    currentList.get(MAPPING_TYPE_RELATION_ANNOTATION)
                        .add(currentObject);
                    unknownAncestors = 0;
                  }
                  // check for group: not within word, not within relation, not
                  // within groupAnnotation
                } else if ((currentList.get(MAPPING_TYPE_WORD).isEmpty())
                    && (currentList.get(MAPPING_TYPE_RELATION).isEmpty())
                    && (currentList.get(MAPPING_TYPE_GROUP_ANNOTATION)
                        .isEmpty())
                    && (tmpCurrentType = groupTypes.get(qname)) != null) {
                  currentObject = new MtasParserObject(tmpCurrentType);
                  collectAttributes(currentObject, streamReader);
                  currentObject.setUnknownAncestorNumber(unknownAncestors);
                  currentObject.setRealOffsetStart(lastOffset);
                  if (!prevalidateObject(currentObject, currentList)) {
                    unknownAncestors++;
                  } else {
                    currentType = tmpCurrentType;
                    currentList.get(MAPPING_TYPE_GROUP).add(currentObject);
                    unknownAncestors = 0;
                  }
                  // check for group annotation: not within word, not within
                  // relation, but within group
                } else if ((currentList.get(MAPPING_TYPE_WORD).isEmpty())
                    && (currentList.get(MAPPING_TYPE_RELATION).isEmpty())
                    && (!currentList.get(MAPPING_TYPE_GROUP).isEmpty())
                    && (tmpCurrentType = groupAnnotationTypes
                        .get(qname)) != null) {
                  currentObject = new MtasParserObject(tmpCurrentType);
                  collectAttributes(currentObject, streamReader);
                  currentObject.setUnknownAncestorNumber(unknownAncestors);
                  currentObject.setRealOffsetStart(lastOffset);
                  if (!prevalidateObject(currentObject, currentList)) {
                    unknownAncestors++;
                  } else {
                    currentType = tmpCurrentType;
                    currentList.get(MAPPING_TYPE_GROUP_ANNOTATION)
                        .add(currentObject);
                    unknownAncestors = 0;
                  }
                  // check for word: not within relation, not within
                  // groupAnnotation, not within word, not within wordAnnotation
                } else if ((currentList.get(MAPPING_TYPE_RELATION).isEmpty())
                    && (currentList.get(MAPPING_TYPE_GROUP_ANNOTATION)
                        .isEmpty())
                    && (currentList.get(MAPPING_TYPE_WORD).isEmpty())
                    && (currentList.get(MAPPING_TYPE_WORD_ANNOTATION).isEmpty())
                    && (tmpCurrentType = wordTypes.get(qname)) != null) {
                  currentObject = new MtasParserObject(tmpCurrentType);
                  collectAttributes(currentObject, streamReader);
                  currentObject.setUnknownAncestorNumber(unknownAncestors);
                  currentObject.setOffsetStart(lastOffset);
                  currentObject.setRealOffsetStart(lastOffset);
                  if (!prevalidateObject(currentObject, currentList)) {
                    unknownAncestors++;
                  } else {
                    currentType = tmpCurrentType;
                    currentObject.addPosition(position.getAndIncrement());
                    currentList.get(MAPPING_TYPE_WORD).add(currentObject);
                    unknownAncestors = 0;
                  }
                  // check for word annotation: not within relation, not within
                  // groupAnnotation, but within word
                } else if ((currentList.get(MAPPING_TYPE_RELATION).isEmpty())
                    && (currentList.get(MAPPING_TYPE_GROUP_ANNOTATION)
                        .isEmpty())
                    && (!currentList.get(MAPPING_TYPE_WORD).isEmpty())
                    && (tmpCurrentType = wordAnnotationTypes
                        .get(qname)) != null) {
                  currentObject = new MtasParserObject(tmpCurrentType);
                  collectAttributes(currentObject, streamReader);
                  currentObject.addPositions(currentList.get(MAPPING_TYPE_WORD)
                      .get((currentList.get(MAPPING_TYPE_WORD).size() - 1))
                      .getPositions());
                  currentObject.setUnknownAncestorNumber(unknownAncestors);
                  currentObject.setRealOffsetStart(lastOffset);
                  if (!prevalidateObject(currentObject, currentList)) {
                    unknownAncestors++;
                  } else {
                    currentType = tmpCurrentType;
                    currentList.get(MAPPING_TYPE_WORD_ANNOTATION)
                        .add(currentObject);
                    unknownAncestors = 0;
                  }
                  // check for references: within relation
                } else if (!currentList.get(MAPPING_TYPE_RELATION).isEmpty()
                    && (tmpCurrentType = refTypes.get(qname)) != null) {
                  currentObject = new MtasParserObject(tmpCurrentType);
                  collectAttributes(currentObject, streamReader);
                  currentObject.setUnknownAncestorNumber(unknownAncestors);
                  currentObject.setRealOffsetStart(lastOffset);
                  if (!prevalidateObject(currentObject, currentList)) {
                    unknownAncestors++;
                  } else {
                    currentType = tmpCurrentType;
                    currentList.get(MAPPING_TYPE_REF).add(currentObject);
                    unknownAncestors = 0;
                    // add reference to ancestor relations
                    for (MtasParserObject currentRelation : currentList
                        .get(MAPPING_TYPE_RELATION)) {
                      currentRelation.addRefId(currentObject
                          .getAttribute(currentType.getRefAttributeName()));
                      // register mapping for relation (for recursive relations)
                      SortedSet<String> keyMapList;
                      if (currentRelation.getId() != null) {
                        if (relationKeyMap
                            .containsKey(currentRelation.getId())) {
                          keyMapList = relationKeyMap
                              .get(currentRelation.getId());
                        } else {
                          keyMapList = new TreeSet<>();
                          relationKeyMap.put(currentRelation.getId(),
                              keyMapList);
                        }
                        keyMapList.add(currentObject
                            .getAttribute(currentType.getRefAttributeName()));
                      }
                    }
                  }
                } else {
                  unknownAncestors++;
                }
                // check for start content
              } else if (qname.equals(getQName(contentTag))) {
                parsingContent = true;
                // unexpected
              } else if (!allowNonContent) {
                throw new MtasParserException(
                    "Unexpected " + qname.getLocalPart() + " in document");
              }
            }
            // set offset (end of start-element)
            lastOffset = streamReader.getLocation().getCharacterOffset();
            break;
          case XMLStreamConstants.END_ELEMENT:
            // set offset (end of end-element)
            lastOffset = streamReader.getLocation().getCharacterOffset();
            // get data
            qname = streamReader.getName();
            // parse content
            if (parsingContent) {
              if (unknownAncestors > 0) {
                unknownAncestors--;
                // check for reference: because otherwise currentList should
                // contain no references
              } else if (!currentList.get(MAPPING_TYPE_REF).isEmpty()) {
                if ((currentType = refTypes.get(qname)) != null) {
                  currentObject = currentList.get(MAPPING_TYPE_REF)
                      .remove(currentList.get(MAPPING_TYPE_REF).size() - 1);
                  assert currentObject.getType()
                      .equals(currentType) : "object expected to be "
                          + currentObject.getType().getName() + ", not "
                          + currentType.getName();
                  assert unknownAncestors == 0 : "error in administration "
                      + currentObject.getType().getName();
                  // ignore text and realOffset: not relevant
                  idPositions.put(currentObject.getId(),
                      currentObject.getPositions());
                  idOffsets.put(currentObject.getId(),
                      currentObject.getOffset());
                  currentObject.updateMappings(idPositions, idOffsets);
                  unknownAncestors = currentObject.getUnknownAncestorNumber();
                  computeMappingsFromObject(mtasTokenIdFactory, currentObject,
                      currentList, updateList);
                } else {
                  // this shouldn't happen
                }
                // check for wordAnnotation: because otherwise currentList
                // should contain no wordAnnotations
              } else if (!currentList.get(MAPPING_TYPE_WORD_ANNOTATION)
                  .isEmpty()) {
                if ((currentType = wordAnnotationTypes.get(qname)) != null) {
                  currentObject = currentList.get(MAPPING_TYPE_WORD_ANNOTATION)
                      .remove(
                          currentList.get(MAPPING_TYPE_WORD_ANNOTATION).size()
                              - 1);
                  assert currentObject.getType()
                      .equals(currentType) : "object expected to be "
                          + currentObject.getType().getName() + ", not "
                          + currentType.getName();
                  assert unknownAncestors == 0 : "error in administration "
                      + currentObject.getType().getName();
                  currentObject.setRealOffsetEnd(lastOffset);
                  idPositions.put(currentObject.getId(),
                      currentObject.getPositions());
                  idOffsets.put(currentObject.getId(),
                      currentObject.getOffset());
                  // offset always null, so update later with word (should be
                  // possible)
                  if ((currentObject.getId() != null)
                      && (!currentList.get(MAPPING_TYPE_WORD).isEmpty())) {
                    currentList.get(MAPPING_TYPE_WORD)
                        .get((currentList.get(MAPPING_TYPE_WORD).size() - 1))
                        .addUpdateableIdWithOffset(currentObject.getId());
                  }
                  currentObject.updateMappings(idPositions, idOffsets);
                  unknownAncestors = currentObject.getUnknownAncestorNumber();
                  computeMappingsFromObject(mtasTokenIdFactory, currentObject,
                      currentList, updateList);
                } else {
                  // this shouldn't happen
                }
                // check for word: because otherwise currentList should contain
                // no words
              } else if (!currentList.get(MAPPING_TYPE_WORD).isEmpty()) {
                if ((currentType = wordTypes.get(qname)) != null) {
                  currentObject = currentList.get(MAPPING_TYPE_WORD)
                      .remove(currentList.get(MAPPING_TYPE_WORD).size() - 1);
                  assert currentObject.getType()
                      .equals(currentType) : "object expected to be "
                          + currentObject.getType().getName() + ", not "
                          + currentType.getName();
                  assert unknownAncestors == 0 : "error in administration "
                      + currentObject.getType().getName();
                  currentObject.setOffsetEnd(lastOffset);
                  currentObject.setRealOffsetEnd(lastOffset);
                  // update ancestor groups with position and offset
                  for (MtasParserObject currentGroup : currentList
                      .get(MAPPING_TYPE_GROUP)) {
                    currentGroup.addPositions(currentObject.getPositions());
                    currentGroup.addOffsetStart(currentObject.getOffsetStart());
                    currentGroup.addOffsetEnd(currentObject.getOffsetEnd());
                  }
                  idPositions.put(currentObject.getId(),
                      currentObject.getPositions());
                  idOffsets.put(currentObject.getId(),
                      currentObject.getOffset());
                  currentObject.updateMappings(idPositions, idOffsets);
                  unknownAncestors = currentObject.getUnknownAncestorNumber();
                  computeMappingsFromObject(mtasTokenIdFactory, currentObject,
                      currentList, updateList);
                } else {
                  // this shouldn't happen
                }
                // check for group annotation: because otherwise currentList
                // should contain no groupAnnotations
              } else if (!currentList.get(MAPPING_TYPE_GROUP_ANNOTATION)
                  .isEmpty()) {
                if ((currentType = groupAnnotationTypes.get(qname)) != null) {
                  currentObject = currentList.get(MAPPING_TYPE_GROUP_ANNOTATION)
                      .remove(
                          currentList.get(MAPPING_TYPE_GROUP_ANNOTATION).size()
                              - 1);
                  assert currentObject.getType()
                      .equals(currentType) : "object expected to be "
                          + currentObject.getType().getName() + ", not "
                          + currentType.getName();
                  assert unknownAncestors == 0 : "error in administration "
                      + currentObject.getType().getName();
                  currentObject.setRealOffsetEnd(lastOffset);
                  idPositions.put(currentObject.getId(),
                      currentObject.getPositions());
                  idOffsets.put(currentObject.getId(),
                      currentObject.getOffset());
                  currentObject.updateMappings(idPositions, idOffsets);
                  unknownAncestors = currentObject.getUnknownAncestorNumber();
                  computeMappingsFromObject(mtasTokenIdFactory, currentObject,
                      currentList, updateList);
                } else {
                  // this shouldn't happen
                }
                // check for relation annotation
              } else if (!currentList.get(MAPPING_TYPE_RELATION_ANNOTATION)
                  .isEmpty()) {
                if ((currentType = relationAnnotationTypes
                    .get(qname)) != null) {
                  currentObject = currentList
                      .get(MAPPING_TYPE_RELATION_ANNOTATION).remove(currentList
                          .get(MAPPING_TYPE_RELATION_ANNOTATION).size() - 1);
                  assert currentObject.getType()
                      .equals(currentType) : "object expected to be "
                          + currentObject.getType().getName() + ", not "
                          + currentType.getName();
                  assert unknownAncestors == 0 : "error in administration "
                      + currentObject.getType().getName();
                  currentObject.setRealOffsetEnd(lastOffset);
                  idPositions.put(currentObject.getId(),
                      currentObject.getPositions());
                  idOffsets.put(currentObject.getId(),
                      currentObject.getOffset());
                  currentObject.updateMappings(idPositions, idOffsets);
                  unknownAncestors = currentObject.getUnknownAncestorNumber();
                  computeMappingsFromObject(mtasTokenIdFactory, currentObject,
                      currentList, updateList);
                } else {
                  // this shouldn't happen
                }
                // check for relation
              } else if (!currentList.get(MAPPING_TYPE_RELATION).isEmpty()) {
                if ((currentType = relationTypes.get(qname)) != null) {
                  currentObject = currentList.get(MAPPING_TYPE_RELATION).remove(
                      currentList.get(MAPPING_TYPE_RELATION).size() - 1);
                  assert currentObject.getType()
                      .equals(currentType) : "object expected to be "
                          + currentObject.getType().getName() + ", not "
                          + currentType.getName();
                  assert unknownAncestors == 0 : "error in administration "
                      + currentObject.getType().getName();
                  // ignore text: should not occur
                  currentObject.setRealOffsetEnd(lastOffset);
                  idPositions.put(currentObject.getId(),
                      currentObject.getPositions());
                  idOffsets.put(currentObject.getId(),
                      currentObject.getOffset());
                  currentObject.updateMappings(idPositions, idOffsets);
                  unknownAncestors = currentObject.getUnknownAncestorNumber();
                  computeMappingsFromObject(mtasTokenIdFactory, currentObject,
                      currentList, updateList);
                } else {
                  // this shouldn't happen
                }
                // check for group
              } else if (!currentList.get(MAPPING_TYPE_GROUP).isEmpty()) {
                if ((currentType = groupTypes.get(qname)) != null) {
                  currentObject = currentList.get(MAPPING_TYPE_GROUP)
                      .remove(currentList.get(MAPPING_TYPE_GROUP).size() - 1);
                  assert currentObject.getType()
                      .equals(currentType) : "object expected to be "
                          + currentObject.getType().getName() + ", not "
                          + currentType.getName();
                  assert unknownAncestors == 0 : "error in administration "
                      + currentObject.getType().getName();
                  // ignore text: should not occur
                  currentObject.setRealOffsetEnd(lastOffset);
                  idPositions.put(currentObject.getId(),
                      currentObject.getPositions());
                  idOffsets.put(currentObject.getId(),
                      currentObject.getOffset());
                  currentObject.updateMappings(idPositions, idOffsets);
                  unknownAncestors = currentObject.getUnknownAncestorNumber();
                  computeMappingsFromObject(mtasTokenIdFactory, currentObject,
                      currentList, updateList);
                } else {
                  unknownAncestors--;
                }
              } else if (qname.equals(getQName("text"))) {
                parsingContent = false;
                assert unknownAncestors == 0 : "error in administration unknownAncestors";
                assert currentList.get(MAPPING_TYPE_REF)
                    .isEmpty() : "error in administration references";
                assert currentList.get(MAPPING_TYPE_GROUP)
                    .isEmpty() : "error in administration groups";
                assert currentList.get(MAPPING_TYPE_GROUP_ANNOTATION)
                    .isEmpty() : "error in administration groupAnnotations";
                assert currentList.get(MAPPING_TYPE_WORD)
                    .isEmpty() : "error in administration words";
                assert currentList.get(MAPPING_TYPE_WORD_ANNOTATION)
                    .isEmpty() : "error in administration wordAnnotations";
                assert currentList.get(MAPPING_TYPE_RELATION)
                    .isEmpty() : "error in administration relations";
                assert currentList.get(MAPPING_TYPE_RELATION_ANNOTATION)
                    .isEmpty() : "error in administration relationAnnotations";
              }
            }
            // forget text
            textContent = null;
            break;
          case XMLStreamConstants.CHARACTERS:
            // set offset (end of start-element)
            lastOffset = streamReader.getLocation().getCharacterOffset();
            // check for text
            if (streamReader.hasText()) {
              textContent = streamReader.getText();
            }
            if (currentObject != null && unknownAncestors.equals(0)) {
              currentObject.addText(textContent);
            }
            break;
          default:
            break;
          }
          if (!streamReader.hasNext()) {
            break;
          }
          event = streamReader.next();
        }
      } finally {
        streamReader.close();
      }
      // final checks
      assert unknownAncestors == 0 : "error in administration unknownAncestors";
      assert hasRoot : "no " + rootTag;
    } catch (XMLStreamException e) {
      log.debug(e);      
      throw new MtasParserException("No valid XML: " + e.getMessage());
    }

    // update tokens with variable
    for (Entry<Integer, Set<String>> updateItem : updateList
        .get(UPDATE_TYPE_VARIABLE).entrySet()) {
      MtasToken token = tokenCollection.get(updateItem.getKey());
      String encodedPrefix = token.getPrefix();
      String encodedPostfix = token.getPostfix();
      token.setValue(decodeAndUpdateWithVariables(encodedPrefix, encodedPostfix,
          variables));
    }
    // update tokens with offset
    for (Entry<Integer, Set<String>> updateItem : updateList
        .get(UPDATE_TYPE_OFFSET).entrySet()) {
      Set<String> refIdList = new HashSet<>();
      for (String refId : updateItem.getValue()) {
        if (idPositions.containsKey(refId)) {
          refIdList.add(refId);
        }
        if (relationKeyMap.containsKey(refId)) {
          refIdList.addAll(recursiveCollect(refId, relationKeyMap, 10));
        }
      }
      for (String refId : refIdList) {
        Integer[] refOffset = idOffsets.get(refId);
        Integer tokenId = updateItem.getKey();
        if (tokenId != null && refOffset != null) {
          MtasToken token = tokenCollection.get(tokenId);
          token.addOffset(refOffset[0], refOffset[1]);
        }
      }
    }
    // update tokens with position
    for (Entry<Integer, Set<String>> updateItem : updateList
        .get(UPDATE_TYPE_POSITION).entrySet()) {
      HashSet<String> refIdList = new HashSet<>();
      for (String refId : updateItem.getValue()) {
        if (idPositions.containsKey(refId)) {
          refIdList.add(refId);
        }
        if (relationKeyMap.containsKey(refId)) {
          refIdList.addAll(recursiveCollect(refId, relationKeyMap, 10));
        }
      }
      for (String refId : refIdList) {
        Set<Integer> refPositions = idPositions.get(refId);
        Integer tokenId = updateItem.getKey();
        if (tokenId != null && refPositions != null) {
          MtasToken token = tokenCollection.get(tokenId);
          token.addPositions(refPositions);
        }
      }
    }
    // final check
    tokenCollection.check(autorepair, makeunique);
    return tokenCollection;
  }