code: def _makeTags(tagStr, xml,
                suppress_LT=Suppress("<"),
                suppress_GT=Suppress(">")):
      
      if isinstance(tagStr,basestring):
          resname = tagStr
          tagStr = Keyword(tagStr, caseless=not xml)
      else:
          resname = tagStr.name
  
      tagAttrName = Word(alphas,alphanums+"_-:")
      if (xml):
          tagAttrValue = dblQuotedString.copy().setParseAction( removeQuotes )
          openTag = (suppress_LT
                     + tagStr("tag")
                     + Dict(ZeroOrMore(Group(tagAttrName + Suppress("=") + tagAttrValue )))
                     + Optional("/", default=[False])("empty").setParseAction(lambda s,l,t:t[0]=='/')
                     + suppress_GT)
      else:
          tagAttrValue = quotedString.copy().setParseAction( removeQuotes ) | Word(printables, excludeChars=">")
          openTag = (suppress_LT
                     + tagStr("tag")
                     + Dict(ZeroOrMore(Group(tagAttrName.setParseAction(downcaseTokens)
                                             + Optional(Suppress("=") + tagAttrValue))))
                     + Optional("/",default=[False])("empty").setParseAction(lambda s,l,t:t[0]=='/')
                     + suppress_GT)
      closeTag = Combine(_L("</") + tagStr + ">", adjacent=False)
  
      openTag.setName("<%s>" % resname)
      # add start<tagname> results name in parse action now that ungrouped names are not reported at two levels
      openTag.addParseAction(lambda t: t.__setitem__("start"+"".join(resname.replace(":"," ").title().split()), t.copy()))
      closeTag = closeTag("end"+"".join(resname.replace(":"," ").title().split())).setName("</%s>" % resname)
      openTag.tag = resname
      closeTag.tag = resname
      openTag.tag_body = SkipTo(closeTag())
      return openTag, closeTag
docs: Internal helper to construct opening and closing tag expressions, given a tag name