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>
我有一个 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>