数据库有如下字段,这是你可以利用的所有辅助信息..Id(自增),Title,parentId(父接点),orderId(排序),ParentPath(所有父结点),depth(深度,从0开始,根结点是0),child(子结点数)
解释一下orderId. orderId字段一定是按整数顺序排的,每一级有单独的排序.如果某级有8个子结点,这8个接点的排序一定是1-8,他父结点的Child是8.
parentpath. 如果 4是2的孩子.2是1的孩子.那么4的parentPath就是0,1,2,4,(这里会包括自己)
说明一下要求.我先帮大家解释一下.
根接点前无任务符号.
第二级前面是1个符号. 这个结点前的符号究竟是 └ 还是 ├ 这取决于他是不是最后一个结点是的话就是└ ,
第三级结点前有两个符号,第三个结点前是什么符号就复杂了.大家自己看吧.
其实就是不停的判断它的父接点来完成.这样要是在数据库里操作.太费资源了,不知道有没有好的算法啊.
parentId 父节点id就这两个参数就足以处理title前的符号了.自己把自己表结构里的数据定义好好理理SELECT charBeforeTitle =
/*若是根*/
CASE WHEN parentID IS NULL /*这里依具你的数据定义,根目级的父ID设置也可能是0*/ THEN '| '
/*若非根,且有子项*/
WHEN Child!=0 THEN REPLICATE('| ',depth-1) +
/*若是同级最后一个*/
CASE WHEN NOT EXISTS(SELECT 1 FROM tb WHERE parendID=a.parendID AND orderid>a.orderID) THEN '|_'
/*若非同级最后一个*/
ELSE '|-'
END
/*若非根且无子项*/
ELSE REPLICATE('| ',depth-1) +
/*若是同级最后一个*/
CASE WHEN NOT EXISTS(SELECT 1 FROM tb WHERE parendID=a.parendID AND orderid>a.orderID) THEN '|_'
/*若非同级最后一个*/
ELSE '|-'
END
END ,
*
FROM tb ORDER BY .... /*具体怎么写,看你的参数定义*/
我是随手敲的, 不排除手误,另外,输出的字符,我随便打了两个示下意,具体用什么你自己决定.由于只要不是根节点,它们的处理方式都一样,语句又可以简化为SELECT charBeforeTitle =
/*若是根*/
CASE WHEN parentID IS NULL /*这里依具你的数据定义,根目级的父ID设置也可能是0*/ THEN '| '
/*若非根*/
ELSE REPLICATE('|',depth-1) +
/*若是同级最后一个*/
CASE WHEN NOT EXISTS(SELECT 1 FROM tb WHERE parendID=a.parendID AND orderid>a.orderID) THEN '|_'
/*若非同级最后一个*/
ELSE '|-'
END
END ,
*
FROM tb ORDER BY .... /*具体怎么写,看你的参数定义*/
代码调用xsl模版递规实现.另外,从数据库来操作的话,因为你的数据不需要再做什么检索,所以数据库递规代码写了也就没意义了,我就不写了.
test.xml<?xml version="1.0" encoding="utf-8" ?>
<?xml-stylesheet type="text/xsl" href="test.xsl"?>
<classes>
<class id="2" pid="0" depth="0">MSSQL</class>
<class id="3" pid="2" depth="1">T-SQL</class>
<class id="4" pid="3" depth="2">树相关</class>
<class id="5" pid="3" depth="2">行转列或列转行</class>
<class id="6" pid="0" depth="0">WEB开发</class>
<class id="7" pid="6" depth="1">Asp.Net</class>
<class id="8" pid="6" depth="1">Xml.Xsl</class>
<class id="9" pid="2" depth="2">备份恢复</class>
<class id="10" pid="6" depth="1">Javascript</class>
</classes>test.xsl
<?xml version="1.0" encoding="utf-8"?>
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<head>
</head>
<body>
<select>
<xsl:apply-templates select="//class[@pid=0]"/>
</select>
</body>
</html>
</xsl:template>
<xsl:template match="//class">
<xsl:param name="id" select="@id"/>
<xsl:param name="depth" select="@depth"/>
<xsl:param name="name" select="."/>
<option value="{$id}">
<xsl:value-of select="substring('| | | | | | | | | | | | | | | | | | | ',1,$depth*3)" />
<xsl:choose>
<xsl:when test="count(//class[@pid=$id]) > 0">
|-
</xsl:when>
<xsl:otherwise> |-</xsl:otherwise>
</xsl:choose>
<xsl:value-of select="."/>
</option>
<xsl:apply-templates select="//class[@pid=$id]"/>
</xsl:template>
</xsl:transform>
比如:
││ └下学期 第三格是一个空格.因为下学期的父结点是平级结点的最后一个结点.所以为空格.而下学期父父的结点不是最后一个结点所以是│如果这个分类展开到最后你会发现下面不再有"│" 而全部被置换为空格.比如:
├AA
└BB
├AA
└BB
├AA
└BB由此可以找出规律.前面的符号并不由自身结点决定,而是由他的父结点不停的递归得到.
在阿信树的JS里,有一个递归来判断他的父结点.
如果程序由服务端来执行,不论放在程序里还是在存储过程里.这样判断都是一个费资源的判定.fxNode.prototype.indent = function()
{
var s ="";
if(this.parentNode!=null)
s += (this.isLast ? "└ " : "├ ");
var p = this.parentNode;
while(p!=null)
{
if(!p.parentNode)break;
s = (p.isLast ? " " : "│")+s;
p = p.parentNode;
}
return s;
}