首先是一个小小的背景:我使用收集管理软件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降序(每当我添加一集时会增加)。所以我需要对此进行改造:
如何做到这一点(显然这里没有谈论剪切代码)? XSLT可以做所有这些吗?我应该在Perl中查看基于树的解析器吗?这是周末,我在Linux机器上,所以在UNIX上运行的开源解决方案会很好 - Perl中的东西可能是最好的。我该怎么读?
如果我不能在家里这样做,那么,我总是可以在办公室设计一个小型的数据存储工作,但我真的很喜欢一个更简单的解决方案。
谢谢! :)
答案 0 :(得分:2)
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>
这就是结果(看看位置和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>
答案 1 :(得分:1)
您可以使用两个简单的模板获得相同的结果:
item
元素进行排序。item
元素,并使用position()
函数重新计算id
属性。我们将保留所有其他后代节点,但不包括id
的原始item
。使用Saxon 6.5.5测试XSLT 1.0转换
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()[not(self::item)]"/>
<xsl:apply-templates select="item">
<xsl:sort select="@series"/>
<xsl:sort select="@season" data-type="number"/>
<xsl:sort select="@episode" data-type="number"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="item">
<item id="{position()}">
<xsl:apply-templates select="@*[name()!='id']|node()"/>
</item>
</xsl:template>
</xsl:stylesheet>
当以上变换应用于以下输入时(@therealmarv稍微修改为包含子元素):
<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">
<synopsis>It's 1931 and...</synopsis>
</item>
<item
id="2"
name="blabla"
series="c"
season="1"
episode="2">
<synopsis>It's 1931 and...</synopsis>
</item>
<item
id="3"
name="abc"
series="Baccano"
season="2"
episode="1">
<synopsis>It's 1931 and...</synopsis>
</item>
<item
id="4"
name="blabla2"
series="Baccano"
season="1"
episode="2">
<synopsis>It's 1931 and...</synopsis>
</item>
<item
id="5"
name="first of c"
series="c"
season="1"
episode="1">
<synopsis>It's 1931 and...</synopsis>
</item>
</collection>
生成以下输出:
<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">
<synopsis>It's 1931 and...</synopsis>
</item>
<item id="4" name="blabla2" series="Baccano" season="1" episode="2">
<synopsis>It's 1931 and...</synopsis>
</item>
<item id="3" name="abc" series="Baccano" season="2" episode="1">
<synopsis>It's 1931 and...</synopsis>
</item>
<item id="5" name="first of c" series="c" season="1" episode="1">
<synopsis>It's 1931 and...</synopsis>
</item>
<item id="2" name="blabla" series="c" season="1" episode="2">
<synopsis>It's 1931 and...</synopsis>
</item>
</collection>
答案 2 :(得分:0)
XSLT可以做所有这些吗?
是。见下面的子答案
- 按系列排序XML,然后是季节,然后是剧集
是的,您可以使用XSLT对XML进行排序。
http://www.w3schools.com/xsl/xsl_sort.asp
- 相应地更改id属性,从1开始到结束(也基于此重置maxId)
您还可以使用它来编写您想要的任何文本。这意味着您可以替换转换中的数据。
它还可以assign variables,执行if statements,loops,执行XPath查询,拥有built-in function library等等,因此对于您来说它将足够强大想做。
- 将其全部写入与另一种XML相同的格式
...这也意味着你可以用它来编写XML
我应该阅读什么?
XSLT:)
w3schools链接(上面的所有链接)对我来说很充实,但我一般都熟悉XML结构(属性,元素,根元素,内部文本等)。如果您熟悉它,请阅读XSLT。
您还可以查看XmlStarlet,这是一个用于从命令行或shell脚本/批处理文件查询和转换XML的工具(但对于转换,它可能无论如何都使用XSLT)。
答案 3 :(得分:0)
我也会用XSLT做这件事。但是,我的样式表与therealmarv的样式表略有不同。
此XML输入:
<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="2"
>
<synopsis>Blah blah blah...</synopsis>
...
</item>
<item
id="2"
name="some name"
series="Alpha"
season="2"
episode="1"
>
<synopsis>Blah blah blah...</synopsis>
...
</item>
<item
id="3"
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="4"
name="some name"
series="Alpha"
season="1"
episode="1"
>
<synopsis>Blah blah blah...</synopsis>
...
</item>
</collection>
使用此样式表:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="collection">
<collection>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="information"/>
<xsl:apply-templates select="item">
<xsl:sort select="@series" data-type="text"/>
<xsl:sort select="@season" data-type="number"/>
<xsl:sort select="@episode" data-type="number"/>
</xsl:apply-templates>
</collection>
</xsl:template>
<xsl:template match="item">
<item id="{position()}">
<xsl:apply-templates select="@*[not(name()='id')]|node()"/>
</item>
</xsl:template>
</xsl:stylesheet>
生成此输出:
<collection type="GCTVepisodes" items="101" version="1.6.1">
<information>
<maxId>101</maxId>
</information>
<item id="1" name="some name" series="Alpha" season="1" episode="1">
<synopsis>Blah blah blah...</synopsis>
...
</item>
<item id="2" name="some name" series="Alpha" season="2" episode="1">
<synopsis>Blah blah blah...</synopsis>
...
</item>
<item id="3" 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="4" name="The Vice President Doesn't Say Anything about the Possibility of Him Being the Main Character" series="Baccano" season="1" episode="2">
<synopsis>Blah blah blah...</synopsis>
...
</item>
</collection>
根据thealmarv的回答输出:
<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>