首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >按属性对XML进行排序和修改

按属性对XML进行排序和修改
EN

Stack Overflow用户
提问于 2011-07-08 21:36:22
回答 4查看 3.9K关注 0票数 3

首先,我使用一个收集管理软件GCStar来管理我的数字图书馆(漫画书/漫画/电影,你可以说-除了书籍之外,它非常棒)。问题是,它不允许我按多个键对架子进行排序,比如按系列和史诗编号排序。后来添加的剧集总是会在架子上显示得更低,按系列分组。

我对这些配置进行了修改,发现它使用的.gcs文件只不过是一个XML (我对它非常熟悉)。是这样的:

代码语言:javascript
运行
复制
<?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 (每当我添加一个插曲时增加)命令降序。因此,我需要对此进行一个转换,它将:

  1. 将XML按系列排序,然后按季,然后按集排序。
  2. 相应地更改id属性,从1开始到结束(也根据此重新设置maxId )
  3. 将其全部写入相同的格式到另一个XML。

如何做到这一点(显然,这里不涉及剪切粘贴代码)?XSLT可以完成所有这些工作吗?我应该看看Perl中基于树的解析器吗?现在是周末,我在一台Linux机器上,所以在UNIX上运行的开源解决方案很好--用Perl最好。我该读些什么?

如果我不能在家里做这件事,那么,我总是可以在办公室设计一个小的数据传输工作,但是我真的很想要一个更简单的解决方案。

谢谢!:)

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2011-07-08 22:06:56

maxId (和集合中的项)值不应更改,因为您没有删除或添加ids。

如果您想要一个简单的命令行,开放源码的XSLTProc,可以使用libxml2 2/libxslt中的XSLTProc。它几乎可以在每个标准linux上使用。http://xmlsoft.org/XSLT/xsltproc2.html

使用此命令xsltproc transform.xsl input.xml >output.xml

这里有一个解决方案,XSLT转换样式表,应该可以工作;-) (我有足够的空闲时间编写它)

代码语言:javascript
运行
复制
<?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>

我使用这些简化的数据来测试它:

代码语言:javascript
运行
复制
<?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是如何变化的):

代码语言:javascript
运行
复制
<?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>
票数 2
EN

Stack Overflow用户

发布于 2011-07-09 21:43:56

您可以使用两个简单的模板获得相同的结果:

  • 在第一个模板(标识)中,我们可以稍微“定位”应用模板机制,以便对item元素进行排序。
  • 在第二个模板中,我们可以覆盖每个item元素,并使用position()函数重新计算id属性。我们将保留所有其他后代节点的原样,但不包括item的原始item

用Saxon 6.5.5测试XSLT1.0转换

代码语言:javascript
运行
复制
<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,稍微修改一下以包含子元素):

代码语言:javascript
运行
复制
<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>

产生了下列产出:

代码语言:javascript
运行
复制
<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>
票数 1
EN

Stack Overflow用户

发布于 2011-07-08 21:46:41

XSLT可以完成所有这些工作吗?

是。见下面的分答案。

  • 将XML按系列排序,然后按季,然后按集排序。

是的,您可以使用XSLT对XML进行排序。

sort.asp

  • 相应地更改id属性,从1开始到结束(也根据此重新设置maxId )

您也可以使用它来编写任何您想要的文本。这意味着您可以在转换中替换数据。

它还可以赋值变量if语句、do XPath查询、有内置函数库等等,所以它将足够强大到您想要做的事情。

  • 将其全部写入相同的格式到另一个XML。

...Which还意味着您可以使用它来编写XML。

我该读些什么?

XSLT :)

w3schools链接(上面的所有链接)对我来说已经够多了,但是我已经对XML (属性、元素、根元素、内部文本等等)很熟悉了。如果您熟悉这一点,只需阅读XSLT。

您还可以查看XmlStarlet,它是一个用于从命令行或shell脚本/批处理文件中查询和转换XML的工具(尽管对于转换,它可能使用XSLT )。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6630787

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档