TL;DR - 問題: ネストされたfor-each
コンマを正しく印刷することができません。繰り返し続けるケースが 4 つあります。仕事を終わらせるために考えられる方法は他にもありますが、なぜこれがこのように動作しているのかを知りたいと思っています。
質問: パイプは機能するのにカンマは機能しないのはなぜですか?また、最後の要素が時々単独で出力されるのはなぜですか?
概要: ノードの関係を含む XML ドキュメントを JSON 形式に変換して、グラフを視覚化しようとしています。この問題を解決するにはいくつかの方法がありますが、私は最初にノードのリストを生成することを選択しました。そのため、XML ドキュメントをノードの JSON ツリー構造に変換する XSL ファイルがあります。
XML ファイルのスニペットを次に示します。
<?xml version="1.0" ?>
<knowledge_base
xmlns="http://protege.stanford.edu/xml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://protege.stanford.edu/xml http://www.enterprise-architecture.org/xml/essentialreportxml.xsd">
<simple_instance>
<name>Class181</name>
<type>Business_Capability</type>
<own_slot_value>
<slot_reference>business_capability_level</slot_reference>
<value value_type="string">3</value>
</own_slot_value>
<own_slot_value>
<slot_reference>realised_by_business_processes</slot_reference>
<value value_type="simple_instance">Class40041</value>
</own_slot_value>
<own_slot_value>
<slot_reference>supports_business_capabilities</slot_reference>
<value value_type="simple_instance">Class180</value>
<value value_type="simple_instance">Class20022</value>
<value value_type="simple_instance">Class182</value>
</own_slot_value>
<own_slot_value>
<slot_reference>name</slot_reference>
<value value_type="string">Help Desk Service</value>
</own_slot_value>
</simple_instance>
</knowledge_base>
複数のビジネス機能があり、ビジネス機能を親として、その他を子として持つことができます。これが私の XSL ドキュメントの大部分です。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xpath-default-namespace="http://protege.stanford.edu/xml" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xalan="http://xml.apache.org/xslt" xmlns:pro="http://protege.stanford.edu/xml" xmlns:eas="http://www.enterprise-architecture.org/essential" xmlns:functx="http://www.functx.com" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ess="http://www.enterprise-architecture.org/essential/errorview">
<xsl:template match="knowledge_base">
<xsl:call-template name="BuildPage"/>
</xsl:template>
<xsl:template name="BuildPage">
<xsl:param name="pageLabel">Business Capability Graph</xsl:param>
<html>
<head>
<title><xsl:value-of select="$pageLabel"></xsl:value-of></title>
<script src="js/d3.v3.min.js"></script>
<script type="text/javascript">
<xsl:text>
function tree()
{
var json=</xsl:text><xsl:call-template name="getJSON" /><xsl:text>;
console.log(JSON.stringify(json));
}
</xsl:text>
</script>
</head>
<body onload="tree();">
<div id="main"></div>
</body>
</html>
</xsl:template>
<xsl:template name="getJSON">
<xsl:text>{ "nodes" : [</xsl:text>
<!-- Get Business Caps -->
<xsl:call-template name="getNodes">
<xsl:with-param name="nodes" select="/node()/simple_instance[type='Business_Capability']" />
</xsl:call-template>
<xsl:text>]}</xsl:text>
</xsl:template>
<xsl:template name="getNodes">
<xsl:param name="nodes" />
<xsl:for-each select="$nodes">
<xsl:variable name="name" select="own_slot_value[slot_reference='name']/value" />
<xsl:variable name="id" select="current()/name" />
<xsl:variable name="level" select="own_slot_value[slot_reference='business_capability_level']/value" />
<xsl:text>{"name":"</xsl:text><xsl:value-of select="$name" />
<xsl:text>", "id":"</xsl:text><xsl:value-of select="$id" />
<xsl:text>", "level":"</xsl:text><xsl:value-of select="$level" />
<xsl:text>", "data":{</xsl:text>
<xsl:variable name="pcCap_list" select="own_slot_value[slot_reference='supports_business_capabilities']" />
<xsl:text>"pcCap":{</xsl:text>
<xsl:for-each select="/node()/simple_instance[name=$pcCap_list/value]" >
<xsl:variable name="pos" select="position()" />
<xsl:text>"id" : "</xsl:text>
<xsl:value-of select="name" />
<xsl:text> - pos </xsl:text><xsl:value-of select="$pos" />
<xsl:text> - count </xsl:text><xsl:value-of select="count($pcCap_list/value)" />
<xsl:text>"</xsl:text>
</xsl:for-each>
<xsl:text>}}}</xsl:text>
<xsl:if test="position() != count($nodes)">
<xsl:text>, </xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
ドキュメント全体を通して、テンプレートの内部を除いて、xsl:if test=position() != count()
を使用してコンマ (1、2、3) を適切に追加することに成功しました。position()、count()、last()、!=、<、>、=、not(position() = count())、count()-1、count()を使用するなど、さまざまなバリエーションを試しました+1 など、andステートメントと一緒に。以下の同じ 4 つのパターンが引き続き表示されます (XSL 構文エラー、および空のオブジェクトと共に)。for-each
getNodes
xsl:choose
xsl:when
xsl:otherwise
これが私が試したことです。すべては、テンプレート内のインナーの<xsl:text>"</xsl:text>
andの後に配置されました。まず、XSL 入力、何が起こったかの要約、および関連する JSON 出力です。</xsl:for-each>
for-each
getNodes
テスト 1:
<xsl:if test="position() != count($pcCap_list/value)" >
<xsl:text>, </xsl:text>
</xsl:if>
No XSL error. No JS error. But only **last element** is printed.
{
"name": "Help Desk Service",
"id": "Class181",
"level": "3",
"data": {
"pcCap": {
"id": "Class20022 - pos 3 - count 3"
}
}
}
テスト 2:
<xsl:if test="position() = count($pcCap_list/value)" >
<xsl:text>, </xsl:text>
</xsl:if>
No XSL error. JS errors = "Uncaught SyntaxError: Unexpected string report:8" && "Uncaught ReferenceError: tree is not defined report:125". All three are printed as expected with the comma after the third element.
{
"name": "Help Desk Service",
"id": "Class181",
"level": "3",
"data": {
"pcCap": {
"id": "Class180 - pos 1 - count 3""id": "Class182 - pos 2 - count 3""id": "Class20022 - pos 3 - count 3",
}
}
}
テスト 3:
<xsl:if test="position() < count($pcCap_list/value)" >
<xsl:text>, </xsl:text>
</xsl:if>
No XSL error. No JS error. Again, only last item is shown.
{
"name": "Help Desk Service",
"id": "Class181",
"level": "3",
"data": {
"pcCap": {
"id": "Class20022 - pos 3 - count 3"
}
}
}
テスト 4:
<xsl:if test="position() < count($pcCap_list/value)" > <!-- happens with both < and != -->
<xsl:text>| </xsl:text>
</xsl:if>
No XSL error. JS errors = "Uncaught SyntaxError: Unexpected token : report:8" && "Uncaught ReferenceError: tree is not defined report:125". Prints out as expected, with pipes between the elements.
{
"name": "Help Desk Service",
"id": "Class181",
"level": "3",
"data": {
"pcCap": {
"id": "Class180 - pos 1 - count 3"|"id": "Class182 - pos 2 - count 3"|"id": "Class20022 - pos 3 - count 3"
}
}
}
では、パイプは機能するのにコンマが機能しない原因は何でしょうか? また、3 番目の要素が単独で印刷されることがあるのはなぜですか?