Это может быть сделано (и я сделал это), но это все еще оставляет потенциал для странной визуализации разметки, особенно когда применяются стили CSS. Когда я писал это, я делал это в Javascript, но тот же подход и все еще использовался и включает работу с DOM, а не String .
Как видите, он просто проходит и считает найденный текст. Как только предел достигнут, он обрезает любой оставшийся текст в узле (добавляя по желанию эллипсы), а затем останавливает обработку дальнейших дочерних узлов и удаляет всех последующих дядей и великих дядей и т. Д. У любых родителей, бабушек и дедушек и т. Д. Это может (и, возможно, должно ) быть адаптированным для использования немутантного подхода.
Вы можете свободно использовать любые идеи / стратегии / коды, которые вы считаете нужными ниже.
/*
Given a DOM Node truncate the contained text at a certain length.
The truncation happens in a depth-first manner.
Any elements that exist past the exceeded length are removed
(this includes all future children, siblings, cousins and whatever else)
and the text in the element in which the exceed happens is truncated.
NOTES:
- This modifieds the original node.
- This only supports ELEMENT and TEXT node types (other types are ignored)
This function return true if the limit was reached.
*/
truncateNode : function (rootNode, limit, ellipses) {
if (arguments.length < 3) {
ellipses = "..."
}
// returns the length found so far.
// if found >= limit then all FUTURE nodes should be removed
function truncate (node, found) {
var ELEMENT_NODE = 1
var TEXT_NODE = 3
switch (node.nodeType) {
case ELEMENT_NODE:
var child = node.firstChild
while (child) {
found = truncate(child, found)
if (found >= limit) {
// remove all FUTURE elements
while (child.nextSibling) {
child.parentNode.removeChild(child.nextSibling)
}
}
child = child.nextSibling
}
return found
case TEXT_NODE:
var remaining = limit - found
if (node.nodeValue.length < remaining) {
// still room for more (at least one more letter)
return found + node.nodeValue.length
}
node.nodeValue = node.nodeValue.substr(0, remaining) + ellipses
return limit
default:
// no nothing
}
}
return truncate(rootNode, 0)
},
Ну, мне правда скучно. Вот это в C #. Почти то же самое. Все еще должно быть обновлено, чтобы быть немутативным. Упражнение для читателя, бла, бла ...
class Util
{
public static string
LazyWrapper (string html, int limit) {
var d = new XmlDocument();
d.InnerXml = html;
var e = d.FirstChild;
Truncate(e, limit);
return d.InnerXml;
}
public static void
Truncate(XmlNode node, int limit) {
TruncateHelper(node, limit, 0);
}
public static int
TruncateHelper(XmlNode node, int limit, int found) {
switch (node.NodeType) {
case XmlNodeType.Element:
var child = node.FirstChild;
while (child != null) {
found = TruncateHelper(child, limit, found);
if (found >= limit) {
// remove all FUTURE elements
while (child.NextSibling != null) {
child.ParentNode.RemoveChild(child.NextSibling);
}
}
child = child.NextSibling;
}
return found;
case XmlNodeType.Text:
var remaining = limit - found;
if (node.Value.Length < remaining) {
// still room for more (at least one more letter)
return found + node.Value.Length;
}
node.Value = node.Value.Substring(0, remaining);
return limit;
default:
return found;
}
}
}
Использование и результат:
Util.LazyWrapper(@"<p class=""abc-class"">01<x/>23456789<y/></p>", 5)
// => <p class="abc-class">01<x />234</p>