XSLT 仅选择重复嵌套树中的第一个节点。

huangapple go评论56阅读模式
英文:

XSLT select only first node in repeated nested tree

问题

以下是您提供的XML的翻译输出:

一些表示存档层次规则的XML,简短示例:

    <someXML>
      <dependency-rules>
        <name>FONDS
          <dependency-rules>
            <name>CATEGORY</name>
          </dependency-rules>
        </name>
      </dependency-rules>
    </someXML>

期望的输出应该反映层次结构,如下所示:

    FONDS
      CATEGORY

缩进表示FONDS可以有CATEGORYs。我在处理嵌套的重复dependency-rules/name结构时遇到困难。这个XML:

    <?xml version="1.0" encoding="UTF-8" ?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:template match="/">
        <html>
          <body>
            <table>
              <xsl:apply-templates select="//name" />
            </table>
          </body>
        </html>
      </xsl:template>

      <xsl:template match="name" >
        <tr>
          <td><xsl:value-of select="count(ancestor::dependency-rules)" /></td>
          <td><xsl:value-of select="." /></td>
        </tr>
      </xsl:template>

    </xsl:stylesheet>

生成了错误的结果:

    1    FONDS CATEGORY
    2    CATEGORY

当然,它匹配每个级别中的每个<name>。如何只获取每个<dependency-rules>节点中的第一个name?我似乎找不到正确的搜索词来找到类似的示例。解决方案可能非常简单,但对我来说很难找到。

更喜欢XSLT 1.0的解决方案,但不是必需的。
英文:

Some XML that represents the hierarchy rules of an archive, a short sample:

&lt;someXML&gt;
  &lt;dependency-rules&gt;
    &lt;name&gt;FONDS
      &lt;dependency-rules&gt;
        &lt;name&gt;CATEGORY&lt;/name&gt;
      &lt;/dependency-rules&gt;
    &lt;/name&gt;
  &lt;/dependency-rules&gt;
&lt;/someXML&gt;

Desired output should reflect the hierarchy, like this

FONDS
  CATEGORY

The indentation means that a FONDS can have CATEGORYs. I'm struggling with the nested repeated dependency-rules/name construction. This

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?&gt;
&lt;xsl:stylesheet version=&quot;1.0&quot; xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;&gt;
  &lt;xsl:template match=&quot;/&quot;&gt;
    &lt;html&gt;
      &lt;body&gt;
        &lt;table&gt;
          &lt;xsl:apply-templates select=&quot;//name&quot; /&gt;
        &lt;/table&gt;
      &lt;/body&gt;
    &lt;/html&gt;
  &lt;/xsl:template&gt;

  &lt;xsl:template match=&quot;name&quot; &gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;xsl:value-of select=&quot;count(ancestor::dependency-rules)&quot; /&gt;&lt;/td&gt;
      &lt;td&gt;&lt;xsl:value-of select=&quot;.&quot; /&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/xsl:template&gt;

&lt;/xsl:stylesheet&gt;

produces this, which is wrong:

1	FONDS CATEGORY
2	CATEGORY

of course it matches on every &lt;name&gt; in each level. How can I get only the first name in each &lt;dependency-rules&gt; node? I can't seem to find the right words to google for to get a similar example. The solution is probably very easy, but for me, hard to find.

XSLT 1.0 solution preferred, but not vital.

答案1

得分: 2

Your XSLT attempts to create an HTML table, which is not well-suited to display a hierarchical structure such as your XML. If you want the result to be an HTML document, I think you might be better off using an unordered list instead. This would be very easy to generate:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
<xsl:template match="/someXML">
    <html>
        <body>
            <ul>
                <xsl:apply-templates select="dependency-rules"/>
            </ul>
        </body>    
    </html>	
</xsl:template>

<xsl:template match="dependency-rules">
    <li>
        <xsl:value-of select="normalize-space(name/text())"/>
        <ul>
            <xsl:apply-templates select="name/dependency-rules"/>
        </ul>
    </li>
</xsl:template>

</xsl:stylesheet>

Using your input example, the result would be:

<html>
   <body>
      <ul>
         <li>FONDS
            <ul>
               <li>CATEGORY
                  <ul></ul>
               </li>
            </ul>
         </li>
      </ul>
   </body>
</html>

and a browser would display this as:

XSLT 仅选择重复嵌套树中的第一个节点。

If you like, you can make it more pretty by adding some CSS.

P.S. If you're happy with a text result, you could reduce the code to only this:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:strip-space elements="*"/>

<xsl:template match="dependency-rules">
    <xsl:param name="indent"/>
    <xsl:value-of select="$indent"/>
    <xsl:value-of select="normalize-space(name/text())"/>
    <xsl:text>&#10;</xsl:text>
     <xsl:apply-templates select="name/dependency-rules">
         <xsl:with-param name="indent" select="concat($indent, '&#9;')"/>
     </xsl:apply-templates>
</xsl:template>

</xsl:stylesheet>
英文:

Your XSLT attempts to create an HTML table, which is not well-suited to display a hierarchical structure such as your XML. If you want the result to be an HTM document, I think you might be better off using an unordered list instead. This would be very easy to generate:

&lt;xsl:stylesheet version=&quot;1.0&quot; xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;&gt;

&lt;xsl:template match=&quot;/someXML&quot;&gt;
	&lt;html&gt;
		&lt;body&gt;
			&lt;ul&gt;
				&lt;xsl:apply-templates select=&quot;dependency-rules&quot;/&gt;
			&lt;/ul&gt;
		&lt;/body&gt;	
	&lt;/html&gt;	
&lt;/xsl:template&gt;

&lt;xsl:template match=&quot;dependency-rules&quot;&gt;
	&lt;li&gt;
		&lt;xsl:value-of select=&quot;normalize-space(name/text())&quot;/&gt;
		&lt;ul&gt;
        	&lt;xsl:apply-templates select=&quot;name/dependency-rules&quot;/&gt;
		&lt;/ul&gt;
    &lt;/li&gt;
&lt;/xsl:template&gt;

&lt;/xsl:stylesheet&gt;

Using your input example, the result would be:

&lt;html&gt;
   &lt;body&gt;
      &lt;ul&gt;
         &lt;li&gt;FONDS
            &lt;ul&gt;
               &lt;li&gt;CATEGORY
                  &lt;ul&gt;&lt;/ul&gt;
               &lt;/li&gt;
            &lt;/ul&gt;
         &lt;/li&gt;
      &lt;/ul&gt;
   &lt;/body&gt;
&lt;/html&gt;

and a browser would display this as:

XSLT 仅选择重复嵌套树中的第一个节点。

If you like, you can make it more pretty by adding some CSS.


P.S. If you're happy with a text result, you could reduce the code to only this:

&lt;xsl:stylesheet version=&quot;1.0&quot; xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;&gt;
&lt;xsl:output method=&quot;text&quot; encoding=&quot;UTF-8&quot;/&gt;
&lt;xsl:strip-space elements=&quot;*&quot;/&gt;

&lt;xsl:template match=&quot;dependency-rules&quot;&gt;
	&lt;xsl:param name=&quot;indent&quot;/&gt;
    &lt;xsl:value-of select=&quot;$indent&quot;/&gt;
    &lt;xsl:value-of select=&quot;normalize-space(name/text())&quot;/&gt;
    &lt;xsl:text&gt;&amp;#10;&lt;/xsl:text&gt;
     &lt;xsl:apply-templates select=&quot;name/dependency-rules&quot;&gt;
     	&lt;xsl:with-param name=&quot;indent&quot; select=&quot;concat($indent, &#39;&amp;#9;&#39;)&quot;/&gt;
     &lt;/xsl:apply-templates&gt;
&lt;/xsl:template&gt;

&lt;/xsl:stylesheet&gt;

答案2

得分: 1

在每个 <dependency-rules> 节点中,你可以简单地将你的指令:

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

替换为:

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

同时,你可以将你的整个尝试简化为:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
	<html>
		<body>
			<table>
				<xsl:for-each select="//name">
					<tr>
						<td>
							<xsl:value-of select="count(ancestor::dependency-rules)" />
						</td>
						<td>
							<xsl:value-of select="text()" />
						</td>
					</tr>
				</xsl:for-each>
			</table>
		</body>
	</html>
</xsl:template>

</xsl:stylesheet>

然而,这并不能让你更接近你希望通过缩进来表示层级的目标。为此,像 y.arazim 建议的无序列表会更好一些。

英文:

> How can I get only the first name in each <dependency-rules> node?

You could simply replace your instruction:

&lt;xsl:value-of select=&quot;.&quot; /&gt;

with:

&lt;xsl:value-of select=&quot;text()&quot; /&gt;

At the same time you could simplify your entire attempt to just:

&lt;xsl:stylesheet version=&quot;1.0&quot; 
xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;&gt;

&lt;xsl:template match=&quot;/&quot;&gt;
	&lt;html&gt;
		&lt;body&gt;
			&lt;table&gt;
				&lt;xsl:for-each select=&quot;//name&quot;&gt;
					&lt;tr&gt;
						&lt;td&gt;
							&lt;xsl:value-of select=&quot;count(ancestor::dependency-rules)&quot; /&gt;
						&lt;/td&gt;
						&lt;td&gt;
							&lt;xsl:value-of select=&quot;text()&quot; /&gt;
						&lt;/td&gt;
					&lt;/tr&gt;
				&lt;/xsl:for-each&gt;
			&lt;/table&gt;
		&lt;/body&gt;
	&lt;/html&gt;
&lt;/xsl:template&gt;

&lt;/xsl:stylesheet&gt;

However, that doesn't get you any closer to your desired goal of representing the hierarchy by indentation. For this purpose, an unordered list as suggested by y.arazim would be much better.

答案3

得分: -3

为了实现所需的输出,您可以按以下方式修改您的XSLT样式表:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text"/>

  <xsl:template match="/">
    <xsl:apply-templates select="//name[not(ancestor::name)]"/>
  </xsl:template>

  <xsl:template match="name">
    <xsl:param name="indent" select="''"/>
    <xsl:value-of select="$indent"/>
    <xsl:value-of select="normalize-space(.)"/>
    <xsl:text>&#10;</xsl:text>
    <xsl:apply-templates select="ancestor::dependency-rules">
      <xsl:with-param name="indent" select="concat($indent, '  ')"/>
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="dependency-rules">
    <xsl:param name="indent"/>
    <xsl:apply-templates select="name">
      <xsl:with-param name="indent" select="$indent"/>
    </xsl:apply-templates>
  </xsl:template>
</xsl:stylesheet>

此样式表使用递归模板来遍历XML层次结构,并生成带有正确缩进的所需输出。它首先选择顶级的name元素,这些元素没有祖先name,然后递归地应用模板到dependency-rules元素,传递更新后的缩进值。

输出是通过<xsl:output method="text"/>声明生成的,这确保了结果是纯文本而不是HTML。

使用给定的输入XML,输出将是:

FONDS
  CATEGORY

该样式表通过正确处理嵌套的dependency-rules并仅选择每个级别内的第一个name,生成了预期的层次结构。

英文:

To achieve the desired output, you can modify your XSLT stylesheet as follows:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?&gt;
&lt;xsl:stylesheet version=&quot;1.0&quot; xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;&gt;
  &lt;xsl:output method=&quot;text&quot;/&gt;

  &lt;xsl:template match=&quot;/&quot;&gt;
	&lt;xsl:apply-templates select=&quot;//name[not(ancestor::name)]&quot;/&gt;
  &lt;/xsl:template&gt;

  &lt;xsl:template match=&quot;name&quot;&gt;
	&lt;xsl:param name=&quot;indent&quot; select=&quot;&#39;&#39;&quot;/&gt;
	&lt;xsl:value-of select=&quot;$indent&quot;/&gt;
	&lt;xsl:value-of select=&quot;normalize-space(.)&quot;/&gt;
	&lt;xsl:text&gt;&amp;#10;&lt;/xsl:text&gt;
	&lt;xsl:apply-templates select=&quot;ancestor::dependency-rules&quot;&gt;
	  &lt;xsl:with-param name=&quot;indent&quot; select=&quot;concat($indent, &#39;  &#39;)&quot;/&gt;
	&lt;/xsl:apply-templates&gt;
  &lt;/xsl:template&gt;

  &lt;xsl:template match=&quot;dependency-rules&quot;&gt;
	&lt;xsl:param name=&quot;indent&quot;/&gt;
	&lt;xsl:apply-templates select=&quot;name&quot;&gt;
	  &lt;xsl:with-param name=&quot;indent&quot; select=&quot;$indent&quot;/&gt;
	&lt;/xsl:apply-templates&gt;
  &lt;/xsl:template&gt;
&lt;/xsl:stylesheet&gt;

This stylesheet uses recursive templates to traverse the XML hierarchy and generate the desired output with proper indentation. It starts by selecting the top-level name elements that don't have an ancestor name, and then applies templates recursively to the dependency-rules elements, passing the updated indent value.

The output is produced using the &lt;xsl:output method=&quot;text&quot;/&gt; declaration, which ensures that the result is plain text rather than HTML.

With the given input XML, the output will be:

FONDS
  CATEGORY

The stylesheet generates the expected hierarchical structure by correctly handling the nested dependency-rules and selecting only the first name within each level.

huangapple
  • 本文由 发表于 2023年6月30日 03:56:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/76584247.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定