首先是一些背景知识:我使用馆藏管理软件 GCStar 来管理我的数字图书馆(漫画/漫画/电影,随便你怎么说 - 除了书籍之外,它非常棒)。问题是,它不允许我按多个键对货架进行排序,比如按系列和剧集编号。稍后添加的剧集将始终显示在架子的较低位置,并按系列分组。
我仔细检查了配置,发现它使用的 .gcs 文件只不过是一个 XML(我只是粗略地熟悉)。是这样的:
<?xml version="1.0" encoding="UTF-8"?>
<collection type="GCTVepisodes" items="101" version="1.6.1">
<information>
<maxId>101</maxId>
</information>
<item
id="1"
name="The Vice President Doesn't Say Anything about the Possibility of
Him Being the Main Character"
series="Baccano"
season="1"
episode="1"
...
>
<synopsis>It's 1931 and...</synopsis>
...
</item>
<item ...
据我所知,该程序将始终按 ID 降序排列(每当我添加一集时它都会增加)。所以我需要对此进行转换:
- 按系列、季节、剧集对 XML 进行排序
- 相应地更改 id 属性,从 1 到结束(也根据此重置 maxId)
- 将其全部写成与另一个 XML 相同的格式。
如何做到这一点(显然不是在这里谈论剪切粘贴代码)? XSLT 可以做所有这些事情吗?我应该研究 Perl 中基于树的解析器吗?这是周末,我在 Linux 机器上,所以在 UNIX 上运行的开源解决方案会很好——Perl 中的东西可能是最好的。我应该阅读哪些内容?
如果我不能在家做,好吧,我总是可以在办公室设计一个小型数据阶段工作,但我非常想要一个更简单的解决方案。
谢谢! :)
maxId(和集合中的项目)值不应更改,因为您没有删除或添加 ID。
如果您想要一个简单的命令行开源 XSLT 转换器,请使用 libxml2/libxslt 中的 XSLTProc。几乎每个标准 Linux 上都可以使用它。 http://xmlsoft.org/XSLT/xsltproc2.html
使用这个命令xsltproc transform.xsl input.xml >output.xml
这是一个解决方案,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="xml" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- Default: copy everything -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!-- remove items, they will be sorted and inserted later -->
<xsl:template match="/collection/item"/>
<!-- remove id -->
<xsl:template match="/collection/item/@id"/>
<xsl:template match="/collection">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
<!-- copy and sort item by series, then season, then episode -->
<xsl:for-each select="item">
<xsl:sort select="@series" data-type="text"/>
<xsl:sort select="@season" data-type="number"/>
<xsl:sort select="@episode" data-type="number"/>
<xsl:copy>
<xsl:attribute name="id">
<xsl:value-of select="position()"/>
</xsl:attribute>
<!-- copy the rest of item -->
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
我用这个简化的数据来测试它:
<?xml version="1.0" encoding="UTF-8"?>
<collection type="GCTVepisodes" items="5" version="1.6.1">
<information>
<maxId>5</maxId>
</information>
<item
id="1"
name="The Vice President Doesn't Say Anything about the Possibility of
Him Being the Main Character"
series="Baccano"
season="1"
episode="1"/>
<item
id="2"
name="blabla"
series="c"
season="1"
episode="2"/>
<item
id="3"
name="abc"
series="Baccano"
season="2"
episode="1"/>
<item
id="4"
name="blabla2"
series="Baccano"
season="1"
episode="2"/>
<item
id="5"
name="first of c"
series="c"
season="1"
episode="1"/>
</collection>
这是结果(看看 position 和 id 是如何变化的):
<?xml version="1.0" encoding="UTF-8"?>
<collection type="GCTVepisodes" items="5" version="1.6.1">
<information>
<maxId>5</maxId>
</information>
<item id="1" name="The Vice President Doesn't Say Anything about the Possibility of Him Being the Main Character" series="Baccano" season="1" episode="1"/>
<item id="2" name="blabla2" series="Baccano" season="1" episode="2"/>
<item id="3" name="abc" series="Baccano" season="2" episode="1"/>
<item id="4" name="first of c" series="c" season="1" episode="1"/>
<item id="5" name="blabla" series="c" season="1" episode="2"/>
</collection>