แรงจูงใจ:
ตอนแรกฉันคิดที่จะสร้างไบนารีทรีเพราะว่าต้องทำแผนผังโครงสร้างบริษัท วิธีการก่อนหน้านี้คือการวาดภาพโดยตรงโดยใช้ซอฟต์แวร์กราฟิก มันดูดี แต่คุณต้องทาสีใหม่ทุกครั้งที่มีการเปลี่ยนแปลง ในทางกลับกัน การแสดงและเค้าโครงของบรรทัดบนหน้าเว็บค่อนข้างจำกัด การเรียงพิมพ์และการวางตำแหน่งตามข้อมูลที่สร้างขึ้นแบบไดนามิกนั้นทำได้ยากมาก และความสวยงามก็ไม่เป็นที่น่าพอใจ หลังจากพยายามหลายครั้ง ฉันตัดสินใจใช้ XML+XSL สำหรับการดำเนินการข้อมูล ใช้ VML เพื่อตกแต่งเส้นให้สวยงาม และใช้ JAVASCRIPT เพื่อวางตำแหน่งวัตถุ
วัสดุ:
แผนผังแผนผังโครงสร้างของไดรฟ์ข้อมูล XML มี 2 ไฟล์: flow2.xml และ flow2.xsl
ผล:
เรียกดูที่นี่
อธิบาย:
แนวคิดแผนผังไบนารี (1)
<html xmlns:v="urn:schemas-microsoft-com:vml">
<สไตล์>
v:* { พฤติกรรม: url(#default#VML) }
</สไตล์>
<v:group id="group1" name="group1" coordsize = "100,100">
-
</วี:กลุ่ม>
นี่เป็นรูปแบบพื้นฐานของ VML ดังนั้นฉันจะไม่อธิบายรายละเอียดเหล่านี้
XML เป็นโครงสร้างแบบต้นไม้ เมื่อเราอ่านข้อมูลแต่ละรายการ เราจำเป็นต้องอ่าน
แผนผังข้อมูล XML ถูกสำรวจ การดำเนินการแบบเรียกซ้ำเป็นหนึ่งในข้อดีของ XSL
ฉันยังตัดสินใจใช้ XSL หลังจากใช้วิธีการอื่นๆ เพื่อดำเนินการสำรวจเส้นทางแต่กลับล้มเหลว
<โฟลว์รูท>
<vcTitle>ต้นไม้ไบนารี--แผนภาพโครงสร้าง</vcTitle>
<Author>การแล่นเรือใบ</Author>
<อีเมล>[email protected]</อีเมล>
<โฟลว์โหนด>
<iProcess>1</iProcess>
<vcCourse>โหนดแรก</vcCourse>
<iถัดไปใช่>
<โฟลว์โหนด>
<iProcess>2</iProcess>
<vcCourse>โหนดที่สอง</vcCourse>
<iNextใช่>…</iNextใช่>
<iNextNo>…</iNextNo>
</โฟลว์โหนด>
</iถัดไปใช่>
<iNextNo>
<โฟลว์โหนด>
<iProcess>3</iProcess>
<vcCourse>โหนดที่สาม</vcCourse>
<iNextใช่>…</iNextใช่>
<iNextNo>…</iNextNo>
</โฟลว์โหนด>
</iNextNo>
</โฟลว์โหนด>
</โฟลว์รูท>
ตรรกะนั้นง่ายมาก มีโหนดย่อยสองโหนด (2, 3) ใต้โหนดปัจจุบัน (1)
เพียงวางตำแหน่งโหนด 2 และโหนด 3 ที่ด้านซ้ายล่างและด้านขวาล่างของโหนด 1
ที่นี่ฉันใช้สีเขียวและสีแดงเป็นเส้นเชื่อมต่อของโหนดด้านซ้ายและขวาตามลำดับเพื่อให้แสดงผลได้ง่าย
เราได้พูดถึงฟังก์ชันแบบเรียกซ้ำของ XSL ไปแล้ว เพื่อให้เห็นแต่ละขั้นตอนการแสดงผลโดยละเอียดมากขึ้น คุณเพียงแค่ต้องเลียนแบบโค้ดต่อไปนี้และเพิ่มข้อความแจ้งเตือนเท่านั้น
<xsl:แม่แบบที่ตรงกัน="FlowNode">
-
<SCRIPT language="JavaScript1.2">
-
alert('แสดงทีละขั้นตอน');
-
</สคริปต์>
-
</xsl:แม่แบบ>
หลังจากดูสโลว์โมชั่นด้านบนแล้ว คุณเข้าใจความคิดของฉันไหม?
แนวคิดต้นไม้ไบนารี (2)
ความคิดของฉันง่ายมาก:
(1) อ่านข้อมูลของโหนดปัจจุบันและสร้างวัตถุใหม่โดยใช้ VML
กำหนดค่าเริ่มต้นให้กับวัตถุ (เช่น ชื่อ รหัส สไตล์ ฯลฯ)
(2) ใช้การควบคุมสคริปต์เพื่อวางตำแหน่งวัตถุปัจจุบัน (3) เพิ่มลูกศรและเส้นระหว่างโหนดปัจจุบันและโหนดแม่
(4) ค้นหาโหนดลูกของโหนดปัจจุบันต่อไปและวนซ้ำจนจบ
นั่นคือโหนดทั้งหมดถูกสำรวจและต้นไม้ได้ถูกสร้างขึ้น
<xsl:แม่แบบที่ตรงกัน="FlowNode">
-
<xsl:ใช้เทมเพลต />
-
</xsl:แม่แบบ>
<xsl:template match="iNextYes">
<xsl:apply-templates select="./FlowNode" />
</xsl:template>
<xsl:template match="iNextNo">
<xsl:apply-templates select="./FlowNode" />
</xsl:แม่แบบ>
กระบวนการเรียกซ้ำทั้งหมดเสร็จสมบูรณ์โดยสามโมดูลข้างต้น (เทมเพลต)
เทมเพลตแรกเรียกเทมเพลตสองรายการต่อไปนี้เมื่อจับคู่เทมเพลตของแต่ละโหนดย่อยในโหนดปัจจุบัน และเทมเพลตสองรายการหลังเรียกเทมเพลตแรกระหว่างการดำเนินการเฉพาะซึ่งเทียบเท่ากับฟังก์ชันแบบเรียกซ้ำ
ไวยากรณ์:
หากต้องการจับคู่เทมเพลตของแต่ละโหนดย่อยในโหนดปัจจุบัน ให้ใช้รูปแบบพื้นฐานขององค์ประกอบ <xsl:apply-templates />
มิฉะนั้น โหนดที่ตรงกันจะถูกกำหนดโดยค่าของนิพจน์ XPath ในพารามิเตอร์ select เช่น <xsl:apply-templates select="./FlowNode" />
ฟังก์ชันของ (1) และ (2) คือการส่งคืนค่าสตริงของนิพจน์ที่กำหนดโดยพารามิเตอร์ select
เงื่อนไขการค้นหาเหมือนกัน ดังนั้นค่าที่ส่งคืนก็เหมือนกันเช่นกัน
เพียงแต่ว่ารูปแบบการเขียนของพวกเขาจะแตกต่างกันไปขึ้นอยู่กับโอกาสที่พวกเขาใช้
(1) <xsl:value-of select="./iProcess/text()" />
(2) {./iProcess/ข้อความ()}
มีการกำหนดตัวแปรบางตัวไว้ที่นี่ และการวางตำแหน่งของโหนดจะขึ้นอยู่กับตัวแปรเหล่านี้เพื่อเรียกสูตรการคำนวณ
root_left //ระยะขอบด้านซ้ายของ root = ความกว้างที่จัดสรรของใบไม้ทั้งหมด (y*10) + ความกว้างของใบไม้ทั้งหมด (y*50) + ค่าพื้นฐานของระยะขอบด้านซ้าย (10)
root_top //ระยะขอบด้านบนของ root = ค่าพื้นฐานของระยะขอบบน (10)
objOval //วัตถุปัจจุบันเป็นวัตถุ
objOval_iProcess //ค่าขั้นตอนของวัตถุปัจจุบัน
objParentOval //โหนดหลักของวัตถุปัจจุบันคือวัตถุ
objParentOval_iProcess //ค่าขั้นตอนของโหนดหลักของวัตถุปัจจุบัน
objParent_name //ชื่อของโหนดหลักของวัตถุปัจจุบัน
Leaf_left // จำนวนใบซ้ายในโหนดย่อยทั้งหมดของวัตถุปัจจุบัน
Leaf_right // จำนวนการออกจากโหนดย่อยทั้งหมดของวัตถุปัจจุบัน
Leaf_sum //จำนวนใบไม้ในโหนดย่อยทั้งหมดของออบเจ็กต์ปัจจุบัน
Leaf: หมายถึงโหนดปัจจุบันที่ไม่มีโหนดย่อย
สูตรการวางตำแหน่งโหนด:
(1) โหนดปัจจุบันคือโหนดรูท
//ตำแหน่งของราก
SobjOval.style.left=parseInt(root_left);
SobjOval.style.top=parseInt(root_top);
//ฟังก์ชันของฟังก์ชัน parseInt() คือการรับค่าจำนวนเต็ม หากไม่ใช่จะเป็น NAN
//ฟังก์ชันของฟังก์ชัน isNaN() คือการตรวจสอบว่าค่าที่ได้รับจาก parseInt เป็นจำนวนเต็มหรือไม่
(2) โหนดปัจจุบันคือโหนดลูกด้านซ้ายของโหนดหลัก
1) เงื่อนไขในการตัดสินคือ: ชื่อของโหนดหลักของวัตถุปัจจุบัน = 'iNextYes'
-
2) ถ้ามีใบลูกที่ถูกต้อง สูตรคือ
ด้านซ้ายของโหนดปัจจุบัน = ด้านซ้ายของโหนดหลัก - ความกว้างรวมของลีฟลูกด้านขวาของโหนดปัจจุบัน - ความกว้างของโหนดปัจจุบัน
3) หากไม่มีลีฟลูกด้านขวา แต่มีลีฟลูกด้านซ้าย สูตรคือ:
ด้านซ้ายของโหนดปัจจุบัน = ด้านซ้ายของโหนดหลัก - ความกว้างรวมของ leaf ลูกด้านซ้ายของโหนดปัจจุบัน
4) หากโหนดปัจจุบันเป็น leaf สูตรจะเป็น:
ด้านซ้ายของโหนดปัจจุบัน = ด้านซ้ายของโหนดหลัก - ความกว้างของโหนดปัจจุบัน...
(3) โหนดปัจจุบันเป็นโหนดลูกที่ถูกต้องของโหนดหลัก
1) เงื่อนไขในการตัดสินคือ: ชื่อของโหนดหลักของวัตถุปัจจุบัน = 'iNextNo'
-
2) ถ้ามีใบลูกซ้าย สูตรคือ
ด้านซ้ายของโหนดปัจจุบัน = ด้านซ้ายของโหนดหลัก + ความกว้างรวมของลีฟลูกด้านซ้ายของโหนดปัจจุบัน + ความกว้างของโหนดปัจจุบัน
3) หากไม่มีลีฟลูกด้านซ้าย แต่มีลีฟลูกด้านขวา สูตรคือ:
ด้านซ้ายของโหนดปัจจุบัน = ด้านซ้ายของโหนดหลัก + ความกว้างรวมของ leaf ลูกด้านขวาของโหนดปัจจุบัน
4) หากโหนดปัจจุบันเป็น leaf สูตรจะเป็น:
ด้านซ้ายของโหนดปัจจุบัน = ด้านซ้ายของโหนดหลัก + ความกว้างของโหนดปัจจุบัน...
สูตร (2) และ (3) ทั้งสองอยู่ทางด้านซ้ายของโหนดปัจจุบัน และเรายังต้องอยู่ด้านบนสุดของโหนดปัจจุบันด้วย
สูตรที่ง่ายมาก: ด้านบนของโหนดปัจจุบัน = ด้านบนของโหนดหลัก + ออฟเซ็ต (80)
แนวคิดต้นไม้ไบนารี (3)
แนวคิดการวางตำแหน่งสำหรับการเชื่อมต่อสาย:
(1) ค้นหาตำแหน่งของโหนดปัจจุบันและโหนดหลัก (2) ตรวจสอบว่าโหนดปัจจุบันเป็นโหนดลูกด้านซ้ายหรือโหนดลูกด้านขวาของโหนดหลัก (3) วาดเส้น
มีการกำหนดตัวแปรบางตัวไว้ที่นี่
objOval //โหนดปัจจุบันเป็นวัตถุ
objParentOval //โหนดหลักของวัตถุปัจจุบันคือวัตถุ
objLine //บรรทัดปัจจุบันเป็นวัตถุ
สูตรการวางตำแหน่งเส้น:
from="x1,y1" to="x2,y2" เป็นวิธีการวางตำแหน่งบรรทัดใน VML
โหนดปัจจุบันคือโหนดลูกด้านซ้ายของโหนดหลัก ดังนั้นสูตรคือ:
จาก = ด้านซ้ายของโหนดหลัก + ออฟเซ็ต (15) ด้านบนของโหนดหลัก + ออฟเซ็ต (32)
ถึง = ซ้าย + ออฟเซ็ต (30) ของโหนดหลัก ด้านบน - ออฟเซ็ต (2) ของโหนดหลัก
โหนดปัจจุบันคือโหนดลูกด้านขวาของโหนดหลัก ดังนั้นสูตรคือ:
จาก = ด้านซ้ายของโหนดหลัก + ออฟเซ็ต (35) ด้านบนของโหนดหลัก + ออฟเซ็ต (32)
ถึง = ด้านซ้ายของโหนดหลัก + ออฟเซ็ต (20) ด้านบนของโหนดหลัก - ออฟเซ็ต (2)
นั่นคือทั้งหมดที่ฉันสามารถคิดได้
มันจะง่ายกว่ามากถ้าเราเพิ่งสร้างแผนภูมิโครงสร้างบริษัท
ต่อไปนี้เป็นแนวคิดของ Cy Young และฉันจะเจาะลึกลงไปอีกเล็กน้อยบนพื้นฐานของเขา
ขั้นแรกให้คำนวณจำนวนโหนดที่ระดับล่างสุดเพื่อให้ได้ความกว้าง
ตำแหน่งโหนดบนของโหนดควรคำนวณตามความเกี่ยวข้องแบบเรียกซ้ำ
โหนดในแต่ละระดับควรเรียงลำดับตามสังกัด ขั้นแรก ให้ตั้งค่า "ค่าพื้นฐาน" = โหนดควรถูกชดเชยไปทางขวา ค่าด้านซ้ายของแต่ละโหนดที่มีโหนดย่อยจะเท่ากับครึ่งหนึ่งของความกว้างของโหนด เป็นเจ้าของบวกกับมูลค่าพื้นฐาน
Postscript:
ด้วยเหตุผลบางประการ อินเทอร์เน็ตมีสัญญาณไม่ดีในช่วงนี้ ใช้เวลาออฟไลน์มากกว่าออนไลน์
ดังนั้นโค้ดจึงยังไม่ถูกทำให้ง่ายขึ้น จริงๆ แล้วยังมีฟังก์ชันอีกมากมายที่ต้องปรับปรุง เช่น:
คุณต้องเพิ่มเมนูคลิกขวา เมนูคลิกขวามีความสามารถในการสร้างโหนดใหม่ แก้ไขชื่อโหนด เปลี่ยนการเชื่อมโยง ฯลฯ คุณสามารถคลิกขวาที่แต่ละโหนดเพื่อเปิดเมนูคลิกขวาของโหนดนี้ .
อธิบาย:
1) flow2.xml เป็นไฟล์ข้อมูล ฉันเชื่อว่าทุกคนจะไม่มีปัญหา
2) flow2.xsl เป็นไฟล์ฟอร์แมต มีหลายสิ่งที่ต้องใส่ใจ
(1) ในสคริปต์:
(1) <xsl:value-of select="./iProcess/text()" />;
(2) {./iProcess/text()}
ฟังก์ชันของ (1) และ (2) คือการส่งคืนค่าสตริงของนิพจน์ที่กำหนดโดยพารามิเตอร์ select
เงื่อนไขการค้นหาเหมือนกัน ดังนั้นค่าที่ส่งคืนก็เหมือนกันเช่นกัน
เพียงแต่ว่ารูปแบบการเขียนของพวกเขาจะแตกต่างกันไปขึ้นอยู่กับโอกาสที่พวกเขาใช้
<xsl:apply-templates select="ทีม" สั่งซื้อโดย = "blue_ID"/>
ตัวอย่างเช่น เราต้องการสร้างโค้ดต่อไปนี้
<div name="parameter value">เนื้อหา</div>
เราถือว่าชื่อคือ "ชื่อ" และค่าพารามิเตอร์คือค่าของสมุดโหนดย่อยภายใต้โหนดปัจจุบันในข้อมูล XML
วิธีแรกในการเขียนคือเพิ่มชื่อแอตทริบิวต์ก่อน จากนั้นจึงเพิ่มค่าพารามิเตอร์
<div>
<xsl:ชื่อแอตทริบิวต์="ชื่อ">
<xsl:value-of select="./book/text()"/> </xsl:attribute>
เนื้อหา
</div>
วิธีที่สองในการเขียนคือการเพิ่มชื่อแอตทริบิวต์และค่าพารามิเตอร์โดยตรง
<div name="{./book/text()}">Content</div>
สำหรับการใช้งานเฉพาะ คุณสามารถดูตัวอย่างได้ในโค้ดที่ฉันเขียน
XSL อยู่ในมาตรฐานอย่างเป็นทางการ xmlns:xsl=" http://www.w3.org/1999/XSL/Transform "
<xsl:value-of select="./book/text()"/>
ฟังก์ชั่นคือ: เพียงเขียนค่าข้อความของเขาและ
<xsl:value-of select="./book"/>
มันแสดงค่าข้อความและเนื้อหาของโหนดลูกทั้งหมด
คุณสามารถลองใช้และส่งออกโหนดที่มีโหนดย่อยและอีกโหนดที่ไม่มีโหนดย่อยเพื่อดูว่าผลลัพธ์ที่แสดงจะเหมือนกันหรือไม่
(2) หมายเหตุ:
IE5 ไม่รองรับ <tag att="{xpath}">
อยากใช้
<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" ?>
อีกสิ่งหนึ่ง:
Encoding="gb2312" ไม่ค่อยถูกเพิ่มลงในโค้ดที่แสดงในหนังสือเรียน XML ส่วนใหญ่
ดังนั้น เมื่อเราใช้ภาษาจีนใน XML ข้อผิดพลาดจะถูกรายงาน เหตุผลก็คือ การประกาศนี้ไม่ได้เขียนไว้
คำลงท้าย:
สิ่งที่ฉันกำลังพูดถึงนี่คือวิธีคิด หากคุณวาดการเปรียบเทียบ มันจะมีประโยชน์ตามธรรมชาติ