Munging XML 与变量嵌套

Munging XML with variable nesting

我有一个 XML 文档,其中包含一个顶级主题,然后是可选的子主题,然后是 table。我想把整个东西重新组织成一个table,其中主题和副主题是列

来源 1

<topic>
    <title>Some Category</title>
    <topic>
        <title>Some Subcategory</title>
        <table>
            <tr><td>Value 1</td><td>Value 2</td><td>Value 3</td></tr>
            ...
        </table>
    </topic>
    ...
</topic>
...

来源 2

<topic>
    <title>Some Category</title>
    <table>
        <tr><td>Value 1</td><td>Value 2</td><td>Value 3</td></tr>
        ...
    </table>
</topic>

目标 1

<table>
    <tr><td>Some Category</td><td>Some Subcategory</td><td>Value 1</td><td>Value 2</td><td>Value 3</td></tr>
    ...
</table>

目标 2

<table>
    <tr><td>Some Category</td><td>Value 1</td><td>Value 2</td><td>Value 3</td></tr>
    ...
</table>

我刚刚开始学习 XMLStarlet,它似乎是完成这项工作的合适工具,但我还不知道如何处理那个可选的子主题层。

回答我自己的问题。

我想出了如何编写 bash 脚本来执行此操作,但 XSLT 转换似乎更健壮且速度更快。我没有对此进行广泛测试,但这似乎有效。我是 XSLT 的新手,因此请多加注意。

来源

<topic>
    <title>Some Category</title>
    <topic>
        <title>Some Subcategory</title>
        <table>
            <tr><td>Value 1</td><td>Value 2</td><td>Value 3</td></tr>
            ...
        </table>
    </topic>
    ...
</topic>
<topic>
    <title>Some Category</title>
    <table>
        <tr><td>Value 1</td><td>Value 2</td><td>Value 3</td></tr>
        ...
    </table>
</topic>

XSLT

<?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>
<head>
<title>Test doc</title>
</head>
<body>
<xsl:if test="topic/topic">
        <xsl:for-each select="topic">
            <xsl:variable name="topic_title" select="title/text()" /> 
            <xsl:for-each select="topic">
                <xsl:variable name="subtopic_title" select="title/text()" /> <xsl:copy-of select="$topic_title" /> <xsl:copy-of select="$subtopic_title" /> 
                    <xsl:for-each select="//tr">
                        <tr><td><xsl:copy-of select="$topic_title" /></td><td><xsl:copy-of select="$subtopic_title" /></td><xsl:copy-of select="*" /> </tr>
                    </xsl:for-each>
                </table>
            </xsl:for-each>
        </xsl:for-each>
    </xsl:if>
    <xsl:if test="not(topic/topic)">
        <xsl:for-each select="topic">
        <xsl:variable name="topic_title" select="title/text()" /> 
            <xsl:copy-of select="$topic_title" /> 
                <xsl:for-each select="//tr">
                    <tr><td><xsl:copy-of select="$topic_title" /></td><xsl:copy-of select="*" /></tr>
                </xsl:for-each>
            </table>
        </xsl:for-each>
    </xsl:if>
</body></html>
</xsl:template>
</xsl:stylesheet>