Вот таблица стилей XSLT 2.0, которая принимает два параметра: индекс, по которому вы хотите вставить (используя схему индексации XSLT / XPath, где индекс начинается с единицы, а не с нуля), и узлы, которые нужно вставить:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xsd"
version="2.0">
<!-- XPath/XSLT index starts with 1 -->
<xsl:param name="index" as="xsd:integer" select="11"/>
<xsl:param name="new" as="node()+"><e/></xsl:param>
<xsl:variable name="text-to-split" as="text()?"
select="descendant::text()[sum((preceding::text(), .)/string-length(.)) ge $index][1]"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()[. is $text-to-split]">
<xsl:variable name="split-index" as="xsd:integer"
select="$index - sum(preceding::text()/string-length(.))"/>
<xsl:value-of select="substring(., 1, $split-index - 1)"/>
<xsl:copy-of select="$new"/>
<xsl:value-of select="substring(., $split-index)"/>
</xsl:template>
</xsl:stylesheet>
Вы можете использовать Saxon 9 для запуска таблиц стилей XSLT 2.0 с Java.
[редактировать]
Вот попытка решить эту проблему с помощью XSLT 1.0:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<!-- XPath/XSLT index starts with 1 -->
<xsl:param name="index" select="11"/>
<xsl:param name="new"><e/></xsl:param>
<xsl:template name="find-text-to-split">
<xsl:param name="text-nodes"/>
<xsl:variable name="sum">
<xsl:call-template name="make-sum">
<xsl:with-param name="nodes" select="$text-nodes[1]/preceding::text() | $text-nodes[1]"/>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="$sum >= $index">
<xsl:value-of select="generate-id($text-nodes[1])"/>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="find-text-to-split">
<xsl:with-param name="text-nodes" select="$text-nodes[position() > 1]"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="make-sum">
<xsl:param name="nodes"/>
<xsl:param name="length" select="0"/>
<xsl:choose>
<xsl:when test="not($nodes)">
<xsl:value-of select="$length"/>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="make-sum">
<xsl:with-param name="nodes" select="$nodes[position() > 1]"/>
<xsl:with-param name="length" select="$length + string-length($nodes[1])"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:variable name="text-to-split-id">
<xsl:call-template name="find-text-to-split">
<xsl:with-param name="text-nodes" select="descendant::text()"/>
</xsl:call-template>
</xsl:variable>
<xsl:template match="*">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@* | comment() | processing-instruction()">
<xsl:copy/>
</xsl:template>
<xsl:template match="text()">
<xsl:choose>
<xsl:when test="generate-id() = $text-to-split-id">
<xsl:variable name="sum">
<xsl:call-template name="make-sum">
<xsl:with-param name="nodes" select="preceding::text()"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="split-index"
select="$index - $sum"/>
<xsl:value-of select="substring(., 1, $split-index - 1)"/>
<xsl:copy-of select="$new"/>
<xsl:value-of select="substring(., $split-index)"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Обратите внимание, что решение XSLT 1.0 не совсем завершено, оно может привести к переполнению стека, если переданный индекс больше любого существующего текстового индекса в документе.