我有以下XML(簡化結構)平頂樹視圖結構
<Workflow>
<CreateEntity />
<Activity Type="Custom" />
<Activity Type="Condition">
<Activity Type="ConditionBranch">
<UpdateEntity />
</Activity>
<Activity Type="ConditionBranch">
<Activity Type="Custom" />
</Activity>
</Activity>
<Activity Type="Custom" />
</Workflow>
,並希望以這種方式來改造它
<WorkflowProcess>
<Activities>
<!-- static start with known id -->
<Activity Id="StartId" />
<!-- activity from CreateEntity node; id - new GUID -->
<Activity Id="CreateEntityId" />
<!-- activity from Custom activity node; id - new GUID -->
<Activity Id="Custom1Id" />
<!-- so on -->
<Activity Id="ConditionId" />
<Activity Id="UpdateEntityId" />
<Activity Id="Custom2Id" />
<Activity Id="Custom3Id" />
<!-- static end with known id -->
<Activity Id="EndId" />
</Activities>
<Connections>
<Connection Id="new-guid" From="StartId" To="CreateEntityId"/>
<Connection Id="new-guid" From="CreateEntityId" To="Custom1Id"/>
<Connection Id="new-guid" From="Custom1Id" To="ConditionId"/>
<Connection Id="new-guid" From="ConditionId" To="UpdateEntityId"/>
<Connection Id="new-guid" From="ConditionId" To="Custom2Id"/>
<Connection Id="new-guid" From="UpdateEntityId" To="Custom3Id"/>
<Connection Id="new-guid" From="Custom2Id" To="Custom3Id"/>
<Connection Id="new-guid" From="Custom3Id" To="EndId"/>
</Connections>
</WorkflowProcess>
我寫最簡單的部分 - 獲取活動列表並堅持創建連接。
問題是如何構建通過新創建的Id引用我的活動的Connections節點?
我的樣品XSL被等(簡化的)
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:myCustomCode="urn:myExtension">
<xsl:output method="xml" indent="yes"/>
<xsl:param name="startActivityId" select="myCustomCode:NewId()"/>
<xsl:param name="endActivityId" select="myCustomCode:NewId()"/>
<xsl:template match="/">
<WorkflowProcess>
<Activities>
<!-- start -->
<Activity Id="{$startActivityId}" />
<xsl:apply-templates select="Workflow"/>
<!-- end -->
<Activity Id="{$endActivityId}" />
</Activities>
<Connections>
<!-- ???-->
<!-- how to compose these connections? -->
</Connections>
</WorkflowProcess>
</xsl:template>
<xsl:template match="Workflow">
<xsl:apply-templates select="CreateEntity"/>
<xsl:apply-templates select="UpdateEntity"/>
<xsl:apply-templates select="Activity[@Type='Custom']"/>
<xsl:apply-templates select="Activity[@Type='Condition']"/>
</xsl:template>
<xsl:template match="CreateEntity">
<xsl:variable name="activityId" select="myCustomCode:NewId()"/>
<Activity Id="{$activityId}" />
</xsl:template>
<xsl:template match="UpdateEntity">
<xsl:variable name="activityId" select="myCustomCode:NewId()"/>
<Activity Id="{$activityId}" />
</xsl:template>
<xsl:template match="Activity[@Type='Custom']">
<xsl:variable name="activityId" select="myCustomCode:NewId()"/>
<Activity Id="{$activityId}" />
</xsl:template>
<xsl:template match="Activity[@Type='Condition']">
<xsl:variable name="activityId" select="myCustomCode:NewId()"/>
<Activity Id="{$activityId}" />
<xsl:apply-templates select="Activity[@Type='ConditionBranch']"/>
</xsl:template>
<xsl:template match="Activity[@Type='ConditionBranch']">
<xsl:apply-templates select="Workflow"/>
</xsl:template>
</xsl:stylesheet>
更新1: 這裏是描述第一/源XML圖表(和目標太)
更新2: 試圖形式化連接規則已經到了這樣的圖表(與增加了另一個交流tivity例如)
更新3: 這是我的冷杉嘗試:積聚在全局腳本對象連接。由於XSLT中的變量是不可變的,因此我們不能修改它們,所以我使用全局對象來存儲連接(請參閱腳本元素)。所以當我找到一個新的活動時,我在這裏把它連接到全局對象。它允許我通過連接遞歸地構建所有活動。
修改XSL:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:myCustomCode="urn:myExtension"
exclude-result-prefixes="msxsl">
<msxsl:script implements-prefix="myCustomCode" language="C#">
<msxsl:using namespace="System.Text" />
<![CDATA[
public string NewId()
{
return Guid.NewGuid().ToString();
}
private StringBuilder _connections = new StringBuilder();
public void AppendConnection(string from, string to)
{
_connections.AppendFormat("<Connection Id='{0}' From='{1}' To='{2}' />", NewId(), from, to);
}
public string GetConnections()
{
return _connections.ToString();
}
]]>
</msxsl:script>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:param name="startActivityId" select="myCustomCode:NewId()"/>
<xsl:param name="endActivityId" select="myCustomCode:NewId()"/>
<xsl:template match="/">
<WorkflowProcess>
<Activities>
<!-- start -->
<Activity Id="{$startActivityId}" name="start" />
<xsl:apply-templates select="Workflow"/>
<!-- end -->
<Activity Id="{$endActivityId}" name="end" />
</Activities>
<Connections>
<!-- output connections from script global value -->
<xsl:value-of select="myCustomCode:GetConnections()" disable-output-escaping="yes" />
</Connections>
</WorkflowProcess>
</xsl:template>
<xsl:template match="Workflow | Activity[@Type='ConditionBranch']" name="Workflow">
<xsl:apply-templates select="CreateEntity"/>
<xsl:apply-templates select="UpdateEntity"/>
<xsl:apply-templates select="Activity[@Type='Custom']"/>
<xsl:apply-templates select="Activity[@Type='Condition']"/>
</xsl:template>
<xsl:template match="CreateEntity">
<xsl:variable name="activityId" select="myCustomCode:NewId()"/>
<Activity Id="{$activityId}" Type='CreateEntity' />
<!-- build connection to parent -->
<xsl:call-template name="buildConnection">
<xsl:with-param name="childId" select = "$activityId" />
</xsl:call-template>
</xsl:template>
<xsl:template match="UpdateEntity">
<xsl:variable name="activityId" select="myCustomCode:NewId()"/>
<Activity Id="{$activityId}" Type='UpdateEntity' />
<!-- build connection to parent -->
<xsl:call-template name="buildConnection">
<xsl:with-param name="childId" select = "$activityId" />
</xsl:call-template>
</xsl:template>
<xsl:template match="Activity[@Type='Custom']">
<xsl:variable name="activityId" select="myCustomCode:NewId()"/>
<Activity Id="{$activityId}" Type='Custom' />
<!-- build connection to parent -->
<xsl:call-template name="buildConnection">
<xsl:with-param name="childId" select = "$activityId" />
</xsl:call-template>
</xsl:template>
<xsl:template match="Activity[@Type='Condition']">
<xsl:variable name="activityId" select="myCustomCode:NewId()"/>
<Activity Id="{$activityId}" Type='Condition' />
<xsl:apply-templates select="Activity[@Type='ConditionBranch']"/>
<!-- build connection to parent -->
<xsl:call-template name="buildConnection">
<xsl:with-param name="childId" select = "$activityId" />
</xsl:call-template>
</xsl:template>
<!-- find parent and add connection to global script variable -->
<xsl:template name="buildConnection">
<xsl:param name = "childId" />
<!-- the main trick is to get parent id here and pass to my custom function -->
<xsl:apply-templates select="myCustomCode:AppendConnection($childId, 'parentId')"/>
</xsl:template>
</xsl:stylesheet>
我無法弄清楚你如何確定哪個活動連接到哪一個開始。 –
源XML中的活動從上到下排列,因此它們不需要id和連接。目標表單必須具有Id和連接。 – Vladislav
我想可以恢復從子元素向後移動的連接:對於第一個活動父元素是開始元素(該id是已知的)。 – Vladislav