code: public final String toXML(PatternRuleId ruleId, Language language) {
      List<String> filenames = language.getRuleFileNames();
      XPath xpath = XPathFactory.newInstance().newXPath();
      for (String filename : filenames) {
        try (InputStream is = this.getClass().getResourceAsStream(filename)) {
          Document doc = getDocument(is);
          Node ruleNode = (Node) xpath.evaluate("/rules/category/rule[@id='" + ruleId.getId() + "']", doc, XPathConstants.NODE);
          if (ruleNode != null) {
            return nodeToString(ruleNode);
          }
          Node ruleNodeInGroup = (Node) xpath.evaluate("/rules/category/rulegroup/rule[@id='" + ruleId.getId() + "']", doc, XPathConstants.NODE);
          if (ruleNodeInGroup != null) {
            return nodeToString(ruleNodeInGroup);
          }
          if (ruleId.getSubId() != null) {
            NodeList ruleGroupNodes = (NodeList) xpath.evaluate("/rules/category/rulegroup[@id='" + ruleId.getId() + "']/rule", doc, XPathConstants.NODESET);
            if (ruleGroupNodes != null) {
              for (int i = 0; i < ruleGroupNodes.getLength(); i++) {
                if (Integer.toString(i+1).equals(ruleId.getSubId())) {
                  return nodeToString(ruleGroupNodes.item(i));
                }
              }
            }
          } else {
            Node ruleGroupNode = (Node) xpath.evaluate("/rules/category/rulegroup[@id='" + ruleId.getId() + "']", doc, XPathConstants.NODE);
            if (ruleGroupNode != null) {
              return nodeToString(ruleGroupNode);
            }
          }
        } catch (Exception e) {
          throw new RuntimeException("Could not turn rule '" + ruleId + "' for language " + language + " into a string", e);
        }
      }
      throw new RuntimeException("Could not find rule '" + ruleId + "' for language " + language + " in files: " + filenames);
    }
docs: Return the given pattern rule as an indented XML string.
  @since 2.3