protected IRegion getRegion(IDocument document, final int offset) {
    StructuredModelWrapper smw = new StructuredModelWrapper();
    smw.init(document);
    try {
      Document xmlDocument = smw.getDocument();
      if (xmlDocument == null) return null;

      Node n = Utils.findNodeForOffset(xmlDocument, offset);

      if (n == null || !(n instanceof IDOMElement)) return null;

      IDOMElement elem = (IDOMElement) n;
      String tagName = elem.getTagName();
      int start = Utils.getValueStart(elem);
      final int nameStart =
          start + (elem.isEndTag() ? "</" : "<").length(); // $NON-NLS-1$ //$NON-NLS-2$
      final int nameEnd = nameStart + tagName.length();

      if (nameStart > offset || nameEnd <= offset) return null;

      return new Region(nameStart, nameEnd - nameStart);
    } finally {
      smw.dispose();
    }
  }
  /**
   * @param offset
   * @return
   */
  protected IRegion getRegion(IDocument document, int offset) {
    StructuredModelWrapper smw = new StructuredModelWrapper();
    try {
      smw.init(document);
      Document xmlDocument = smw.getDocument();
      if (xmlDocument == null) return null;

      Node n = Utils.findNodeForOffset(xmlDocument, offset);

      if (n == null || !(n instanceof Attr)) return null;
      int start = Utils.getValueStart(n);
      int end = Utils.getValueEnd(n);
      if (start > offset) return null;

      String attrText = document.get(start, end - start);

      StringBuffer sb = new StringBuffer(attrText);
      // find start of css class
      int bStart = offset - start;
      while (bStart >= 0) {
        if (!Character.isJavaIdentifierPart(sb.charAt(bStart))
            && sb.charAt(bStart) != '_'
            && sb.charAt(bStart) != '-'
            && sb.charAt(bStart) != '.') {
          bStart++;
          break;
        }

        if (bStart == 0) break;
        bStart--;
      }
      // find end of css class
      int bEnd = offset - start;
      while (bEnd < sb.length()) {
        if (!Character.isJavaIdentifierPart(sb.charAt(bEnd))
            && sb.charAt(bEnd) != '_'
            && sb.charAt(bEnd) != '-'
            && sb.charAt(bEnd) != '.') break;
        bEnd++;
      }

      final int propStart = bStart + start;
      final int propLength = bEnd - bStart;

      if (propStart > offset || propStart + propLength < offset) return null;
      return new Region(propStart, propLength);
    } catch (BadLocationException x) {
      // ignore
      return null;
    } finally {
      smw.dispose();
    }
  }
  public static IHyperlinkRegion getRegion(IDocument document, final int offset) {
    StructuredModelWrapper smw = new StructuredModelWrapper();
    try {
      smw.init(document);
      Document xmlDocument = smw.getDocument();
      if (xmlDocument == null) return null;

      Node n = Utils.findNodeForOffset(xmlDocument, offset);

      if (n == null || !(n instanceof Attr)) return null;

      int start = Utils.getValueStart(n);
      int end = Utils.getValueEnd(n);

      if (start < 0 || start > offset) return null;

      String attrText = document.get(start, end - start);
      StringBuffer sb = new StringBuffer(attrText);

      // find start of bean property
      int bStart = offset - start;
      while (bStart >= 0) {
        if (!Character.isJavaIdentifierPart(sb.charAt(bStart)) && sb.charAt(bStart) != '.') {
          bStart++;
          break;
        }

        if (bStart == 0) break;
        bStart--;
      }
      // find end of bean property
      int bEnd = offset - start;
      while (bEnd < sb.length()) {
        if (!Character.isJavaIdentifierPart(sb.charAt(bEnd)) && sb.charAt(bEnd) != '.') break;
        bEnd++;
      }

      int propStart = bStart + start;
      int propLength = bEnd - bStart;

      if (propStart > offset || propStart + propLength < offset) return null;

      IHyperlinkRegion region = new HyperlinkRegion(propStart, propLength, null, null, null);
      return region;
    } catch (BadLocationException x) {
      JSFExtensionsPlugin.log("", x); // $NON-NLS-1$
      return null;
    } finally {
      smw.dispose();
    }
  }