docs: protected void buildBookInfoFile(final BuildData buildData, final String bookInfoTemplate) throws BuildProcessingException {
          final ContentSpec contentSpec = buildData.getContentSpec();
          final Map<String, String> overrides = buildData.getBuildOptions().getOverrides();
  
          String bookInfo = bookInfoTemplate.replaceAll(BuilderConstants.ESCAPED_TITLE_REGEX, buildData.getEscapedBookTitle());
  
          // DocBook 5 changed the name of <articleinfo>/<bookinfo> to just <info>
          final String rootElementName;
          if (buildData.getDocBookVersion() == DocBookVersion.DOCBOOK_50) {
              rootElementName = "info";
              bookInfo = bookInfo.replaceAll("<(/)?bookinfo", "<$1info").replaceAll("<(/)?articleinfo", "<$1info");
  
              // Change the corpauthor element to orgname
              bookInfo = bookInfo.replaceAll("<(/)?corpauthor>", "<$1orgname>");
  
              // change the "id" attribute to "xml:id"
              bookInfo = bookInfo.replace("id=\"", "xml:id=\"");
          } else {
              if (contentSpec.getBookType() == BookType.ARTICLE || contentSpec.getBookType() == BookType.ARTICLE_DRAFT) {
                  rootElementName = "articleinfo";
              } else {
                  rootElementName = "bookinfo";
              }
          }
  
          // Replace the book info elements with the data from the content spec
          boolean versionSet = false;
          boolean editionSet = false;
          boolean abstractSet = false;
          boolean subtitleSet = false;
          for (final org.jboss.pressgang.ccms.contentspec.Node node : contentSpec.getNodes()) {
              if (node instanceof KeyValueNode) {
                  final KeyValueNode<?> keyValueNode = (KeyValueNode<?>) node;
                  if (!(keyValueNode.getValue() instanceof String)) {
                      continue;
                  }
  
                  if (CommonConstants.CS_TITLE_TITLE.equalsIgnoreCase(keyValueNode.getKey())) {
                      // Set the book title
                      final String title = DocBookBuildUtilities.getKeyValueNodeText(buildData, keyValueNode);
                      bookInfo = bookInfo.replaceAll(BuilderConstants.TITLE_REGEX,
                              DocBookBuildUtilities.escapeForReplaceAll(DocBookUtilities.escapeForXML(title)));
                  } else if (CommonConstants.CS_SUBTITLE_TITLE.equalsIgnoreCase(keyValueNode.getKey())) {
                      // Set the book subtitle
                      final String subtitle = DocBookBuildUtilities.getKeyValueNodeText(buildData, keyValueNode);
                      bookInfo = bookInfo.replaceAll(BuilderConstants.SUBTITLE_REGEX,
                              contentSpec.getSubtitle() == null ? BuilderConstants.SUBTITLE_DEFAULT : DocBookBuildUtilities
                                      .escapeForReplaceAll(DocBookUtilities.escapeForXML(subtitle)));
                      subtitleSet = true;
                  } else if (CommonConstants.CS_PRODUCT_TITLE.equalsIgnoreCase(keyValueNode.getKey())) {
                      // Set the book product
                      final String product = DocBookBuildUtilities.getKeyValueNodeText(buildData, keyValueNode);
                      bookInfo = bookInfo.replaceAll(BuilderConstants.PRODUCT_REGEX,
                              DocBookBuildUtilities.escapeForReplaceAll(DocBookUtilities.escapeForXML(product)));
                  } else if (CommonConstants.CS_VERSION_TITLE.equalsIgnoreCase(keyValueNode.getKey())) {
                      // Set the book version
                      final String version = DocBookBuildUtilities.getKeyValueNodeText(buildData, keyValueNode);
                      bookInfo = bookInfo.replaceAll(BuilderConstants.VERSION_REGEX, version == null ? "" : version);
                      versionSet = true;
                  } else if (CommonConstants.CS_EDITION_TITLE.equalsIgnoreCase(keyValueNode.getKey())) {
                      // Set the book edition
                      final String edition = DocBookBuildUtilities.getKeyValueNodeText(buildData, keyValueNode);
                      bookInfo = bookInfo.replaceAll(BuilderConstants.EDITION_REGEX, edition);
                  } else if (CommonConstants.CS_ABSTRACT_TITLE.equalsIgnoreCase(keyValueNode.getKey())) {
                      final String description = DocBookBuildUtilities.getKeyValueNodeText(buildData, keyValueNode);
  
                      final String fixedAbstract;
                      if (description.matches("^<(formal|sim)?para>(.|\\s)*")) {
                          fixedAbstract = "<abstract>\n\t\t" + description + "\n\t</abstract>\n";
                      } else {
                          fixedAbstract = "<abstract>\n\t\t<para>\n\t\t\t" + description + "\n\t\t</para>\n\t</abstract>\n";
                      }
  
                      // Set the book abstract
                      bookInfo = bookInfo.replaceAll(BuilderConstants.ABSTRACT_REGEX,
                              DocBookBuildUtilities.escapeForReplaceAll(DocBookUtilities.escapeForXML(fixedAbstract)));
                      abstractSet = true;
                  }
              }
          }
  
          // Apply the null value defaults for version, edition and abstract
          if (!subtitleSet) {
              bookInfo = bookInfo.replaceAll(BuilderConstants.SUBTITLE_REGEX, BuilderConstants.SUBTITLE_DEFAULT);
          }
          if (!versionSet) {
              bookInfo = bookInfo.replaceAll(BuilderConstants.VERSION_REGEX, "");
          }
          if (!editionSet) {
              bookInfo = bookInfo.replaceAll("<edition>.*</edition>(\r)?\n", "");
          }
          if (!abstractSet) {
              final String fixedAbstract;
              if (contentSpec.getAbstractTopic() != null) {
                  fixedAbstract = DocBookBuildUtilities.convertDocumentToFormattedString(contentSpec.getAbstractTopic().getXMLDocument(),
                          getXMLFormatProperties());
              } else {
                  fixedAbstract = BuilderConstants.DEFAULT_ABSTRACT;
              }
  
              bookInfo = bookInfo.replaceAll(BuilderConstants.ABSTRACT_REGEX, DocBookBuildUtilities.escapeForReplaceAll(fixedAbstract));
          }
  
          // Get the pubsnumber
          final String pubsNumber = overrides.containsKey(CSConstants.PUBSNUMBER_OVERRIDE) ? overrides.get(
                  CSConstants.PUBSNUMBER_OVERRIDE) : (contentSpec.getPubsNumber() == null ? BuilderConstants.DEFAULT_PUBSNUMBER :
                  contentSpec.getPubsNumber().toString());
  
          // pubsnumber is different is docbook 5
          if (buildData.getDocBookVersion() == DocBookVersion.DOCBOOK_50) {
              bookInfo = bookInfo.replaceAll(BuilderConstants.PUBSNUMBER_REGEX, "<biblioid class=\"pubsnumber\">" + pubsNumber +
                      "</biblioid>");
          } else {
              bookInfo = bookInfo.replaceAll(BuilderConstants.PUBSNUMBER_REGEX, "<pubsnumber>" + pubsNumber + "</pubsnumber>");
          }
  
          // Set the book to have a Legal Notice
          bookInfo = bookInfo.replaceAll(BuilderConstants.LEGAL_NOTICE_REGEX, BuilderConstants.LEGAL_NOTICE_XML);
  
          if (!isNullOrEmpty(contentSpec.getBrandLogo())) {
              final String fixedLogoPath = contentSpec.getBrandLogo().contains(
                      "Common_Content/images/") ? contentSpec.getBrandLogo() : ("Common_Content/images/" + contentSpec.getBrandLogo());
              bookInfo = bookInfo.replaceFirst("<imagedata.*?/>", "<imagedata fileref=\"" + fixedLogoPath + "\" />");
          }
  
          // Add the preamble to the book info
          bookInfo = DocBookBuildUtilities.addDocBookPreamble(buildData.getDocBookVersion(), bookInfo, rootElementName,
                  buildData.getEntityFileName());
  
          if (contentSpec.getBookType() == BookType.ARTICLE || contentSpec.getBookType() == BookType.ARTICLE_DRAFT) {
              addToZip(buildData.getBookLocaleFolder() + "Article_Info.xml", bookInfo, buildData);
          } else {
              addToZip(buildData.getBookLocaleFolder() + "Book_Info.xml", bookInfo, buildData);
          }
      }