XML扁平编号索引转换为实际树结构 – XSLT

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

XML flat numbered index to real tree structure - XSLT

问题

XML树形编号索引到真实树结构 - XSLT

我正在尝试制作一个带有逻辑嵌套编号的索引树,每个部分在逻辑上嵌套在彼此内部。我正在使用XSLT

2.0,并一直尝试使用for-each-group ... group-starting-with,但效果甚微。

这是一个样本输入的XML:

  1. <DOC>
  2. <section class="AB">
  3. <h1>Real section header</h1>
  4. <p><b>1. heading</b></p>
  5. <p>Some text here.</p>
  6. <p>More text.</p>
  7. <p><b>1.1. setting</b></p>
  8. <p>More words.</p>
  9. <p><b>1.2. fremmer</b></p>
  10. <p><b>1.2.1. point</b></p>
  11. <p>We are sailing.</p>
  12. <p>Whisky in the jar.</p>
  13. <p><b>1.2.2.</b></p>
  14. <p>Johnny is the man.</p>
  15. <p><b>1.2.3.</b></p>
  16. <p>And we go on and on.</p>
  17. <ul>
  18. <li>List item one</li>
  19. <li>List item two</li>
  20. <li>List item three</li>
  21. </ul>
  22. <p><b>2. Another heading</b></p>
  23. <p>Here is the accompanying text.</p>
  24. <table>
  25. <tr>
  26. <td>1</td>
  27. <td>Bla bla bla.</td>
  28. </tr>
  29. <tr>
  30. <td>2</td>
  31. <td>BlaX bla bla.</td>
  32. </tr>
  33. <tr>
  34. <td>3</td>
  35. <td>BlaY bla bla.</td>
  36. </tr>
  37. </table>
  38. <p><b>3. Last heading</b></p>
  39. <p>Here is the accompanying text right now.</p>
  40. </section>
  41. </DOC>

这是输出应该是什么样子的:

  1. <DOC>
  2. <section class="AB">
  3. <h1>Real section header</h1>
  4. <section>
  5. <h1>1. heading</h1>
  6. <p>Some text here.</p>
  7. <p>More text.</p>
  8. <section>
  9. <h1>1.1. setting</h1>
  10. <p>More words.</p>
  11. </section>
  12. <section>
  13. <h1>1.2. fremmer</h1>
  14. <section>
  15. <h1>1.2.1. point</h1>
  16. <p>We are sailling.</p>
  17. <p>Whisky in the jar.</p>
  18. </section>
  19. <section>
  20. <h1>1.2.2.</h1>
  21. <p>Johnny is the man.</p>
  22. </section>
  23. <section>
  24. <h1>1.2.3.</h1>
  25. <p>And we go on and on.</p>
  26. <ul>
  27. <li>List item one</li>
  28. <li>List item two</li>
  29. <li>List item three</li>
  30. </ul>
  31. </section>
  32. </section>
  33. </section>
  34. <section>
  35. <h1>2. Another heading</h1>
  36. <p>Here is the accompanying text.</p>
  37. <table>
  38. <tr>
  39. <td>1</td>
  40. <td>Bla bla bla.</td>
  41. </tr>
  42. <tr>
  43. <td>2</td>
  44. <td>BlaX bla bla.</td>
  45. </tr>
  46. <tr>
  47. <td>3</td>
  48. <td>BlaY bla bla.</td>
  49. </tr>
  50. </table>
  51. </section>
  52. <section>
  53. <h1>3. Last heading</h1>
  54. <p>Here is the accompanying text right now.</p>
  55. </section>
  56. </section>
  57. </DOC>
英文:

XML flat numbered index to real tree structure - XSLT

I am trying to make an index tree with numbered section logically nested within each other. I am using XSLT

2.0 and have been trying to use for-each-group ... group-starting-with to little avail.

Here is a sample input XML:

  1. <DOC>
  2. <section class="AB">
  3. <h1>Real section header</h1>
  4. <p><b>1. heading</b></p>
  5. <p>Some text here.</p>
  6. <p>More text.</p>
  7. <p><b>1.1. setting</b></p>
  8. <p>More words.</p>
  9. <p><b>1.2. fremmer</b></p>
  10. <p><b>1.2.1. point</b></p>
  11. <p>We are sailing.</p>
  12. <p>Whisky in the jar.</p>
  13. <p><b>1.2.2.</b></p>
  14. <p>Johnny is the man.</p>
  15. <p><b>1.2.3.</b></p>
  16. <p>And we go on and on.</p>
  17. <ul>
  18. <li>List item one</li>
  19. <li>List item two</li>
  20. <li>List item three</li>
  21. </ul>
  22. <p><b>2. Another heading</b></p>
  23. <p>Here is the accompanying text.</p>
  24. <table>
  25. <tr>
  26. <td>1</td>
  27. <td>Bla bla bla.</td>
  28. </tr>
  29. <tr>
  30. <td>2</td>
  31. <td>BlaX bla bla.</td>
  32. </tr>
  33. <tr>
  34. <td>3</td>
  35. <td>BlaY bla bla.</td>
  36. </tr>
  37. </table>
  38. <p><b>3. Last heading</b></p>
  39. <p>Here is the accompanying text right now.</p>
  40. </section>
  41. </DOC>

And this is what the output should be:

  1. <DOC>
  2. <section class="AB">
  3. <h1>Real section header</h1>
  4. <section>
  5. <h1>1. heading</h1>
  6. <p>Some text here.</p>
  7. <p>More text.</p>
  8. <section>
  9. <h1>1.1. setting</h1>
  10. <p>More words.</p>
  11. </section>
  12. <section>
  13. <h1>1.2. fremmer</h1>
  14. <section>
  15. <h1>1.2.1. underpunkt</h1>
  16. <p>We are sailling.</p>
  17. <p>Whisky in the jar.</p>
  18. </section>
  19. <section>
  20. <h1>1.2.2.</h1>
  21. <p>Johnny is the man.</p>
  22. </section>
  23. <section>
  24. <h1>1.2.3.</h1>
  25. <p>And we go on and on.</p>
  26. <ul>
  27. <li>List item one</li>
  28. <li>List item two</li>
  29. <li>List item three</li>
  30. </ul>
  31. </section>
  32. </section>
  33. </section>
  34. <section>
  35. <h1>2. Another heading</h1>
  36. <p>Here is the accompanying text.</p>
  37. <table>
  38. <tr>
  39. <td>1</td>
  40. <td>Bla bla bla.</td>
  41. </tr>
  42. <tr>
  43. <td>2</td>
  44. <td>BlaX bla bla.</td>
  45. </tr>
  46. <tr>
  47. <td>3</td>
  48. <td>BlaY bla bla.</td>
  49. </tr>
  50. </table>
  51. </section>
  52. <section>
  53. <h1>3. Last heading</h1>
  54. <p>Here is the accompanying text right now.</p>
  55. </section>
  56. </section>
  57. </DOC>

答案1

得分: 0

最终看起来好像你的输入与我评论中的建议不完全符合,因为内部的 p/b 没有空格和标题编号后的文本,但你当然可以使用不同的测试,例如:

  1. <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  2. xmlns:xs="http://www.w3.org/2001/XMLSchema"
  3. xmlns:mf="http://example.com/mf"
  4. exclude-result-prefixes="#all"
  5. version="3.0">
  6. <xsl:function name="mf:group" as="node()*">
  7. <xsl:param name="nodes" as="node()*"/>
  8. <xsl:param name="level" as="xs:integer"/>
  9. <xsl:for-each-group select="$nodes" group-starting-with="p[b[string-length(translate(replace(., '^([0-9.]+)[^0-9.]*$', '$1'), '0123456789', '')) = $level]]">
  10. <xsl:choose>
  11. <xsl:when test="self::p[b[string-length(translate(replace(., '^([0-9.]+)[^0-9.]*$', '$1'), '0123456789', '')) = $level]]">
  12. <section>
  13. <xsl:apply-templates select="."/>
  14. <xsl:sequence select="mf:group(tail(current-group()), $level + 1)"/>
  15. </section>
  16. </xsl:when>
  17. <xsl:otherwise>
  18. <xsl:apply-templates select="current-group()"/>
  19. </xsl:otherwise>
  20. </xsl:choose>
  21. </xsl:for-each-group>
  22. </xsl:function>
  23. <xsl:template match="section

    ">

  24. <xsl:copy>

  25. <xsl:apply-templates select="@*"/>

  26. <xsl:sequence select="mf:group(node(), 1)"/>

  27. </xsl:copy>

  28. </xsl:template>

  29. <xsl:template match="section/p[b]">

  30. <h1>

  31. <xsl:apply-templates/>

  32. </h1>

  33. </xsl:template>

  34. <xsl:template match="section/p/b">

  35. <xsl:apply-templates/>

  36. </xsl:template>

  37. <xsl:mode on-no-match="shallow-copy"/>

  38. <xsl:output method="xml" indent="yes" html-version="5"/>

  39. <xsl:strip-space elements="*"/>

  40. </xsl:stylesheet>

这是 XSLT 3,对于 XSLT 2.0,你需要将 xsl:mode 声明拆分为如下:

  1. <xsl:template match="@* | node()">
  2. <xsl:copy>
  3. <xsl:apply-templates select="@* | node()"/>
  4. </xsl:copy>
  5. </xsl:template>

并且在使用 tail(current-group()) 时改为使用 subsequence(current-group(), 2)

英文:

In the end it looks as if your input doesn't quite meet the suggestion from my comment as the inner p/bs don't have a space and text after the heading number but you can of course use a different test e.g.

  1. &lt;xsl:stylesheet xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;
  2. xmlns:xs=&quot;http://www.w3.org/2001/XMLSchema&quot;
  3. xmlns:mf=&quot;http://example.com/mf&quot;
  4. exclude-result-prefixes=&quot;#all&quot;
  5. version=&quot;3.0&quot;&gt;
  6. &lt;xsl:function name=&quot;mf:group&quot; as=&quot;node()*&quot;&gt;
  7. &lt;xsl:param name=&quot;nodes&quot; as=&quot;node()*&quot;/&gt;
  8. &lt;xsl:param name=&quot;level&quot; as=&quot;xs:integer&quot;/&gt;
  9. &lt;xsl:for-each-group select=&quot;$nodes&quot; group-starting-with=&quot;p[b[string-length(translate(replace(., &#39;^([0-9.]+)[^0-9.]*$&#39;, &#39;$1&#39;), &#39;0123456789&#39;, &#39;&#39;)) = $level]]&quot;&gt;
  10. &lt;xsl:choose&gt;
  11. &lt;xsl:when test=&quot;self::p[b[string-length(translate(replace(., &#39;^([0-9.]+)[^0-9.]*$&#39;, &#39;$1&#39;), &#39;0123456789&#39;, &#39;&#39;)) = $level]]&quot;&gt;
  12. &lt;section&gt;
  13. &lt;xsl:apply-templates select=&quot;.&quot;/&gt;
  14. &lt;xsl:sequence select=&quot;mf:group(tail(current-group()), $level + 1)&quot;/&gt;
  15. &lt;/section&gt;
  16. &lt;/xsl:when&gt;
  17. &lt;xsl:otherwise&gt;
  18. &lt;xsl:apply-templates select=&quot;current-group()&quot;/&gt;
  19. &lt;/xsl:otherwise&gt;
  20. &lt;/xsl:choose&gt;
  21. &lt;/xsl:for-each-group&gt;
  22. &lt;/xsl:function&gt;
  23. &lt;xsl:template match=&quot;section

    &quot;&gt;

  24. &lt;xsl:copy&gt;

  25. &lt;xsl:apply-templates select=&quot;@*&quot;/&gt;

  26. &lt;xsl:sequence select=&quot;mf:group(node(), 1)&quot;/&gt;

  27. &lt;/xsl:copy&gt;

  28. &lt;/xsl:template&gt;

  29. &lt;xsl:template match=&quot;section/p[b]&quot;&gt;

  30. &lt;h1&gt;

  31. &lt;xsl:apply-templates/&gt;

  32. &lt;/h1&gt;

  33. &lt;/xsl:template&gt;

  34. &lt;xsl:template match=&quot;section/p/b&quot;&gt;

  35. &lt;xsl:apply-templates/&gt;

  36. &lt;/xsl:template&gt;

  37. &lt;xsl:mode on-no-match=&quot;shallow-copy&quot;/&gt;

  38. &lt;xsl:output method=&quot;xml&quot; indent=&quot;yes&quot; html-version=&quot;5&quot;/&gt;

  39. &lt;xsl:strip-space elements=&quot;*&quot;/&gt;

  40. &lt;/xsl:stylesheet&gt;

That is XSLT 3, for XSLT 2.0 you would need to spell out the xsl:mode declaration as e.g.

  1. &lt;xsl:template match=&quot;@* | node()&quot;&gt;
  2. &lt;xsl:copy&gt;
  3. &lt;xsl:apply-templates select=&quot;@* | node()&quot;/&gt;
  4. &lt;/xsl:copy&gt;
  5. &lt;/xsl:template&gt;

and use subsequence(current-group(), 2) instead of tail(current-group()).

huangapple
  • 本文由 发表于 2023年4月20日 01:32:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/76057333.html
匿名

发表评论

匿名网友

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

确定