Maison >développement back-end >Tutoriel XML/RSS >Conseils pratiques sur les volumes XML (5) : Diagramme arborescent

Conseils pratiques sur les volumes XML (5) : Diagramme arborescent

黄舟
黄舟original
2017-02-10 16:22:171666parcourir

Motivation :
Au départ, j'avais pensé à créer un arbre binaire car j'avais besoin de réaliser un organigramme de l'entreprise. L’approche précédente consistait à dessiner directement une image à l’aide d’un logiciel graphique. C'est agréable à regarder, mais vous devez en peindre un nouveau à chaque fois qu'il y a des changements. En revanche, l'affichage et la disposition des lignes sur les pages web sont assez limités. La composition et le positionnement basés sur des données générées dynamiquement sont très difficiles et l'esthétique n'est pas satisfaisante. Après plusieurs tentatives, j'ai décidé d'utiliser XML XSL pour les opérations sur les données ; VML pour embellir les lignes et JAVASCRIPT pour positionner les objets.

Matériaux :
Diagramme d'arborescence de structure de volume XML
Il y a 2 fichiers : flow2.xml et flow2.xsl
Effet :
Parcourir ici
Explication :
Binaire idée d'arbre (1)

<html xmlns:v="urn:schemas-microsoft-com:vml">
<STYLE>
v\:* { BEHAVIOR: url(#default#VML) } 
</STYLE>
<v:group id="group1" name="group1" coordsize = "100,100">
…
</v:group>

Ce sont les formats de base de VML, je ne vais donc pas les expliquer en détail.

XML est une structure arborescente. Lorsque nous lisons chaque donnée, nous devons parcourir cette
arborescence de données XML. Les opérations récursives sont l'un des avantages de XSL.
J'ai également
décidé d'utiliser XSL après avoir utilisé diverses autres méthodes pour effectuer des opérations de traversée et j'ai échoué.

<FlowRoot>
<vcTitle>二叉树--结构图</vcTitle>
<Author>Sailflying</Author>
<Email>sailflying@163.net</Email>
<FlowNode>
<iProcess>1</iProcess>
<vcCourse>第一个节点</vcCourse>
<iNextYes>
<FlowNode>
<iProcess>2</iProcess> 
<vcCourse>第二个节点</vcCourse>
<iNextYes>…</iNextYes> 
<iNextNo>…</iNextNo> 
</FlowNode>
</iNextYes> 
<iNextNo>
<FlowNode>
<iProcess>3</iProcess> 
<vcCourse>第三个节点</vcCourse>
<iNextYes>…</iNextYes> 
<iNextNo>…</iNextNo> 
</FlowNode>
</iNextNo> 
</FlowNode>
</FlowRoot>


La logique est très simple, il y a deux nœuds enfants (2, 3) sous le nœud actuel (1).
Positionnez simplement le nœud 2 et le nœud 3 en bas à gauche et en bas à droite du nœud 1.
Ici, j'utilise respectivement le vert et le rouge pour les lignes de connexion des nœuds gauche et droit pour un affichage facile.


Nous avons parlé plus tôt de la fonction récursive de XSL Afin de voir plus clairement chaque étape d'affichage
détaillée, il vous suffit d'imiter le code suivant et d'ajouter une instruction d'alerte.

<xsl:template match="FlowNode">…<SCRIPT language="JavaScript1.2">…alert(&#39;逐步显示&#39;);…</SCRIPT>…</xsl:template>

En regardant le ralenti ci-dessus, pouvez-vous comprendre mes pensées ?



Idée d'arbre binaire (2)
Mon idée est très simple :
(1) Lire les données du nœud actuel et utiliser VML Générer un nouvel objet.
Attribuez une valeur initiale à l'objet (telle que le nom, l'identifiant, le style, etc.)
(2) Utilisez le contrôle de script pour positionner l'objet actuel
(3) Ajoutez une flèche entre le nœud actuel et son nœud parent, line.
(4) Continuez à trouver les nœuds enfants du nœud actuel et bouclez jusqu'à la fin.
C'est-à-dire que tous les nœuds ont été parcourus et l'arborescence a été générée.

<xsl:template match="FlowNode">…<xsl:apply-templates />…</xsl:template> 
<xsl:template match="iNextYes"><xsl:apply-templates select="./FlowNode" /></xsl:template>
<xsl:template match="iNextNo"><xsl:apply-templates select="./FlowNode" /></xsl:template>

L'ensemble du processus récursif est complété par les trois modules ci-dessus (modèle).
Le premier modèle
appelle les deux modèles suivants lors de la correspondance avec le modèle de chaque sous-nœud dans le nœud actuel ; et les deux derniers modèles appellent le premier modèle lorsque
est exécuté , ce qui équivaut à un. fonction récursive.

Syntaxe :

Pour faire correspondre tour à tour le modèle de chaque nœud enfant dans le nœud actuel, la forme de base de l'élément
doit être utilisée8eae74506dee144daa9808add7137a4b.
Sinon, le nœud correspondant est déterminé par la valeur de l'expression XPath dans le paramètre de sélection
, tel que a4ff84829f0c6689de63321b743d97eb

Les fonctions de (1) et (2) doivent renvoyer la valeur de chaîne de l'expression donnée par le paramètre select.
Leurs conditions de recherche sont les mêmes, donc les valeurs renvoyées sont également les mêmes.
C'est juste que les occasions où ils sont utilisés sont différentes, et leurs formes d'écriture sont également différentes.


(1) 4e771df31dc7c4d0227645e23ff3015c
(2) {./iProcess/text()}


Certaines variables sont définies ici, et le positionnement du nœud se base sur ces variables pour appeler la formule de calcul.

root_left //La marge gauche de la racine = la largeur allouée de toutes les feuilles (y*10) La largeur de toutes les feuilles (y*50) La valeur de base de la marge gauche (10)
root_top //La marge supérieure de la racine =Valeur de base de la marge supérieure (10)
objOval //L'objet actuel est un objet
objOval_iProcess //La valeur de pas de l'objet actuel
objParentOval //Le parent le nœud de l'objet actuel est un objet
objParentOval_iProcess //La valeur de pas du nœud parent de l'objet actuel
objParent_name //Le nom du nœud parent de l'objet actuel
Leaf_left //Le nombre de feuilles gauches parmi toutes nœuds enfants de l'objet actuel
Leaf_right //Tous les nœuds enfants de l'objet actuel Le nombre de feuilles à droite dans
Leaf_sum //Le nombre de feuilles dans tous les nœuds enfants de l'objet actuel

Feuille : signifie que le nœud actuel n'a pas de nœuds enfants


Formule de positionnement du nœud :

(1) Le nœud actuel est le nœud racine

//根的位置
SobjOval.style.left=parseInt(root_left);
SobjOval.style.top=parseInt(root_top);
//parseInt() 函数的作用是取整数值,如果不是则为NAN
//isNaN()函数的作用是判断parseInt取得的是否为整数


(2) Le nœud actuel est le nœud enfant gauche du nœud parent

1) La condition de jugement est : Le nom de l'objet actuel parent node='iNextYes'

2) S'il y a une feuille enfant droite, la formule est :
La gauche du nœud actuel=parent La gauche du nœud - la largeur totale de la droite feuille enfant du nœud actuel - la largeur du nœud actuel

3) S'il n'y a pas de feuille enfant droite, mais que la feuille enfant gauche existe, la formule est :
gauche du nœud actuel = gauche du nœud parent - la largeur totale de la feuille enfant gauche du nœud actuel

4) Si le nœud actuel lui-même est une feuille, la formule est :
à gauche du nœud actuel = à gauche du nœud parent - à gauche du nœud actuel Largeur

(3) Le nœud actuel est le nœud enfant droit du nœud parent

1) Les conditions de jugement sont : Objet courant Le nom du nœud parent='iNextNo'

2) S'il y a une feuille enfant gauche, la formule est :
La gauche de la nœud actuel = la gauche du nœud parent La largeur totale de la feuille enfant gauche du nœud actuel Le nœud actuel La largeur de

3)如果不存在左边子叶子,但存在右边子叶子,则公式为:
当前节点的left=父节点的left + 当前节点的右边子叶子的总宽度

4)如果当前节点本身就是叶子,则公式为:
当前节点的left=父节点的left + 当前节点的宽度

 

(2)和(3)的公式都是得到当前节点的left,我们还需要得到当前节点的top
很简单的公式:当前节点的top=父节点的top + 偏移量(80)

 

二叉树思路(3)
连接线条的定位思路:
(1)找到当前节点和父节点的位置
(2)判断当前节点是父节点的左边子节点,还是右边子节点
(3)画线条

这里定义了一些变量。


objOval //当前节点,是一个object
objParentOval //当前对象的父节点,是一个object
objLine //当前线条,是一个object


线条的定位公式:


from="x1,y1" to="x2,y2" 是 VML 里定位线条的方式

当前节点是父节点的左边子节点,则公式为:
from = 父节点的left + 偏移量(15) , 父节点的top + 偏移量(32)
to = 父节点的left + 偏移量(30) , 父节点的top - 偏移量(2)

当前节点是父节点的右边子节点,则公式为:
from = 父节点的left + 偏移量(35) ,父节点的top + 偏移量(32)
to = 父节点的left + 偏移量(20) ,父节点的top - 偏移量(2)


我所能想到的也就这么多了。

如果只是单纯的做一个公司结构图的话,会更简单很多。
下面是赛扬的思路,我也是在他的基础上深入一点而已。

首先计算最下层节点个数,得出宽度,
然后应该根据节点的从属关系计算其上层节点位置,递归。
每一层级的节点要按从属关系先排序
首先设“基本值”=节点应向右偏移量
每个包含子节点的节点的left值等于它所拥有的节点所占宽度的一半加上基本值

后话:

最近不知为何,网络一直都不好。断线的时间比在线的时间多。
所以没对代码简化,其实,要完善的功能还有很多,比如:
需要加右键菜单
右键菜单内含新建节点、修改节点名称、改变关联关系等
在每一个节点上都可右键打开这个节点的右键菜单

讲解:
1)flow2.xml 是数据文件,相信大家都不会有问题。
2)flow2.xsl 是格式文件,有几个地方要注意。 
(1)脚本中:

(1) <xsl:value-of select="./iProcess/text()" /> ;(2) {./iProcess/text()}

(1)和(2)的作用都是返回由 select 参数给出的表达式的字符串值。
他们的搜索条件相同,所以返回的值也一样。
只不过是使用的场合不同,他们的书写形式也就不一样。

<xsl:apply-templates select="team" order-by="blue_ID"/>


比如我们想生成以下代码
bba950c6d155ac5073309a6041296da9内容94b3e26ee717c64999d7867364b1b4a3


我们假设名称为“name”,参数值为XML数据中当前节点下面的子节点book的值


第一种写法是先加属性名称,再加参数值

<p>
<xsl:attribute name="name">
<xsl:value-of select="./book/text()"/> </xsl:attribute>
内容 
</p>

第二种写法是直接加属性名称和参数值

<p name="{./book/text()}">内容</p>

具体的使用你可以看我写的代码中的例子。

XSL在正式的 xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 的标准里

<xsl:value-of select="./book/text()"/>


作用是:只是把他的文本值写出来,而

<xsl:value-of select="./book"/>


是把他的文本值和他的所有子节点的内容显示出来。
大家可以试验一下,输出一个有子节点的,一个无子节点的
看看显示的结果是否相同。


(2)需要注意:

IE5 不支持 c55c83ef8ee979923031582b93a38c44
要用

<tag><xsl:attribute name="att"><xsl:value-of select="xpath"></xsl:attribute>

命名空间要用

xmlns:xsl="http://www.w3.org/TR/WD-xsl"
<?xml version="1.0" encoding="gb2312" ?>

另外说一点:
在大多的XML教科书中所显示的代码中很少会加上encoding="gb2312" ,
因此我们在XML中用到中文的时候会报错,原因就是没有写这个申明。

后记:
这里说的是一种思路。如果触类旁通,自然能够派上用场。 

以上就是XML卷之实战锦囊(5):结构树图的内容,更多相关内容请关注PHP中文网(www.php.cn)!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn