2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.yangtools.yang.parser.rfc6020.repo;
10 import com.google.common.base.Preconditions;
11 import java.util.ArrayDeque;
12 import java.util.Deque;
13 import org.opendaylight.yangtools.yang.parser.spi.source.DeclarationInTextSource;
14 import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
15 import org.slf4j.Logger;
16 import org.slf4j.LoggerFactory;
17 import org.w3c.dom.Document;
18 import org.w3c.dom.Element;
19 import org.w3c.dom.Node;
20 import org.xml.sax.Attributes;
21 import org.xml.sax.Locator;
22 import org.xml.sax.SAXException;
23 import org.xml.sax.helpers.DefaultHandler;
25 // adapted from https://stackoverflow.com/questions/4915422/get-line-number-from-xml-node-java
26 final class StatementSourceReferenceHandler extends DefaultHandler {
27 private static final Logger LOG = LoggerFactory.getLogger(StatementSourceReferenceHandler.class);
28 private static final String USER_DATA_KEY = StatementSourceReference.class.getName();
30 private final Deque<Element> stack = new ArrayDeque<>();
31 private final StringBuilder sb = new StringBuilder();
32 private final Document doc;
33 private final String file;
35 private Locator locator;
37 StatementSourceReferenceHandler(final Document doc, final String file) {
38 this.doc = Preconditions.checkNotNull(doc);
42 static StatementSourceReference extractRef(final Element element) {
43 final Object value = element.getUserData(USER_DATA_KEY);
44 if (value instanceof StatementSourceReference) {
45 return (StatementSourceReference) value;
48 LOG.debug("Ignoring {} attached to key {}", value, USER_DATA_KEY);
54 public void setDocumentLocator(final Locator locator) {
55 // Save the locator, so that it can be used later for line tracking when traversing nodes.
56 this.locator = locator;
60 @SuppressWarnings("checkstyle:parameterName")
61 public void startElement(final String uri, final String localName, final String qName,
62 final Attributes attributes) {
64 final Element el = doc.createElementNS(uri, qName);
65 for (int i = 0, len = attributes.getLength(); i < len; i++) {
66 el.setAttributeNS(attributes.getURI(i), attributes.getQName(i), attributes.getValue(i));
69 final StatementSourceReference ref = DeclarationInTextSource.atPosition(file, locator.getLineNumber(),
70 locator.getColumnNumber());
71 el.setUserData(USER_DATA_KEY, ref, null);
76 @SuppressWarnings("checkstyle:parameterName")
77 public void endElement(final String uri, final String localName, final String qName) {
79 final Element closedEl = stack.pop();
80 Node parentEl = stack.peek();
81 if (parentEl == null) {
86 parentEl.appendChild(closedEl);
90 public void characters(final char[] ch, final int start, final int length) throws SAXException {
91 sb.append(ch, start, length);
94 // Outputs text accumulated under the current node
95 private void addTextIfNeeded() {
96 if (sb.length() > 0) {
97 stack.peek().appendChild(doc.createTextNode(sb.toString()));