我一直在开发Geo应用程序。随着时间的流逝,产品的XML变得有些混乱。在多个环境(例如Dev,Test等)中同步更改时会出现问题。我正在尝试找出一种标准化内容的方法,这样我就可以避免在编辑和合并时出现一些麻烦,从而可以进行富有成效的开发。我知道这听起来很疯狂,而且背景很多,但是让我跳到实际的问题上来。
问题出在这里
应用了多个排序顺序,例如:
d.c.b.a
读为a.b.c.d
或将map.google.com
读为com.google.map
进行排序。<tgt>
元素下的标签应用类似的排序顺序。<scheme>
和<port>
标记,例如对方案标记使用http / https,对端口标记使用80或443,否则保留。另外,如果没有值,请删除,例如<scheme/>
。这里有一些有问题的XML:
XML
<?xml version='1.0' encoding='UTF-8' ?>
<?tapia chrome-version='2.0' ?>
<mapGeo>
<a>blah</a>
<b>blah</b>
<maps>
<mapIndividual>
<src>
<scheme>https</scheme>
<domain>photos.yahoo.com</domain>
<path>somepath</path>
<query>blah</query>
</src>
<loc>C:\var\tmp</loc>
<x>blah</x>
<y>blah</y>
</mapIndividual>
<mapIndividual>
<src>
<scheme>tcp</scheme>
<domain>map.google.com</domain>
<port>80</port>
<path>/value</path>
<query>blah</query>
</src>
<tgt>
<scheme>https</scheme>
<domain>map.google.com</domain>
<port>443</port>
<path>/value</path>
<query>blah</query>
</tgt>
<x>blah</x>
<y>blah</y>
</mapIndividual>
<mapIndividual>
<src>
<scheme>http</scheme>
<domain>*.c.b.a</domain>
<path>somepath</path>
<port>8085</port>
<query>blah</query>
</src>
<tgt>
<domain>r.q.p</domain>
<path>somepath</path>
<query>blah</query>
</tgt>
<x>blah</x>
<y>blah</y>
</mapIndividual>
<mapIndividual>
<src>
<scheme>http</scheme>
<domain>d.c.b.a</domain>
<path>somepath</path>
<port>8085</port>
<query>blah</query>
</src>
<tgt>
<domain>r.q.p</domain>
<path>somepath</path>
<query>blah</query>
</tgt>
<x>blah</x>
<y>blah</y>
</mapIndividual>
<maps>
</mapGeo>
我能够按原样对值进行基本排序,但无法找到生成反向域名的方法。我遇到了XSL扩展,但还没有尝试过。这是我正在研究的解决方案的开始部分,这是非常基础的。
XSL
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="node()">
<xsl:copy>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="maps">
<xsl:copy>
<xsl:apply-templates select="*">
<xsl:sort select="src/domain" />
<xsl:sort select="src/port" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
预期产量
<?xml version='1.0' encoding='UTF-8' ?>
<?tapia chrome-version='2.0' ?>
<mapGeo>
<a>blah</a>
<b>blah</b>
<maps>
<mapIndividual>
<src>
<domain>d.c.b.a</domain>
<path>somepath</path>
<port>8085</port>
<query>blah</query>
</src>
<tgt>
<domain>r.q.p</domain>
<path>somepath</path>
<query>blah</query>
</tgt>
<x>blah</x>
<y>blah</y>
</mapIndividual>
<mapIndividual>
<src>
<domain>*.c.b.a</domain>
<path>path1</path>
<port>8085</port>
<query>blah</query>
</src>
<tgt>
<domain>r.q.p</domain>
<path>path2</path>
<query>blah</query>
</tgt>
<x>blah</x>
<y>blah</y>
</mapIndividual>
<mapIndividual>
<src>
<scheme>tcp</scheme>
<domain>map.google.com</domain>
<path>/value</path>
<query>blah</query>
</src>
<tgt>
<domain>map.google.com</domain>
<path>/value</path>
<query>blah</query>
</tgt>
<x>blah</x>
<y>blah</y>
</mapIndividual>
<mapIndividual>
<src>
<domain>photos.yahoo.com</domain>
<path>somepath</path>
<query>blah</query>
</src>
<loc>C:\var\tmp</loc>
<x>blah</x>
<y>blah</y>
</mapIndividual>
<maps>
</mapGeo>
注意:我更喜欢XSLT 1.0,因为当前环境支持该功能。 XSLT 2.0将是一个加号。
更新:我已经找到了支持XSLT 2.0和XSLT 3.0的解决方案,所以请忽略我先前关于XSLT 1.0的说明。
先谢谢您!
干杯
答案 0 :(得分:0)
我认为使用XSLT 1.0不可能按照您一次查找的相反顺序进行排序。考虑下面的简化示例:
XML
<root>
<item>
<domain>t.q.p</domain>
</item>
<item>
<domain>s.q.p</domain>
</item>
<item>
<domain>photos.yahoo.com</domain>
</item>
<item>
<domain>map.google.com</domain>
</item>
<item>
<domain>aap.google.com</domain>
</item>
<item>
<domain>r.q.p</domain>
</item>
<item>
<domain>*.c.b.a</domain>
</item>
<item>
<domain>d.c.b.a</domain>
</item>
</root>
XSLT 1.0(+ EXSLT节点集)
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root">
<!-- 1st pass -->
<xsl:variable name="items">
<xsl:for-each select="item">
<xsl:copy>
<xsl:attribute name="sort-string">
<xsl:call-template name="reverse-tokens">
<xsl:with-param name="text" select="domain"/>
</xsl:call-template>
</xsl:attribute>
<xsl:copy-of select="@*|node()"/>
</xsl:copy>
</xsl:for-each>
</xsl:variable>
<!-- output -->
<xsl:copy>
<xsl:apply-templates select="exsl:node-set($items)/item">
<xsl:sort select="@sort-string" data-type="text" order="ascending"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="@sort-string"/>
<xsl:template name="reverse-tokens">
<xsl:param name="text"/>
<xsl:param name="delimiter" select="'.'"/>
<xsl:variable name="token" select="substring-before(concat($text, $delimiter), $delimiter)"/>
<xsl:if test="contains($text, $delimiter)">
<!-- recursive call -->
<xsl:call-template name="reverse-tokens">
<xsl:with-param name="text" select="substring-after($text, $delimiter)"/>
</xsl:call-template>
<xsl:value-of select="$delimiter"/>
</xsl:if>
<xsl:choose>
<xsl:when test="$token = '*'">
<xsl:text>zzzz</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$token"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
结果
<?xml version="1.0" encoding="UTF-8"?>
<root>
<item>
<domain>d.c.b.a</domain>
</item>
<item>
<domain>*.c.b.a</domain>
</item>
<item>
<domain>aap.google.com</domain>
</item>
<item>
<domain>map.google.com</domain>
</item>
<item>
<domain>photos.yahoo.com</domain>
</item>
<item>
<domain>r.q.p</domain>
</item>
<item>
<domain>s.q.p</domain>
</item>
<item>
<domain>t.q.p</domain>
</item>
</root>
答案 1 :(得分:0)
此XSLT 1.0样式表(无扩展名)
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<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="maps">
<xsl:copy>
<xsl:apply-templates select="*">
<xsl:sort
select="translate(src/domain,translate(src/domain,'.',''),'')"
order="descending"/>
<xsl:sort
select="
substring-after(
substring-after(
substring-after(translate(src/domain,'*','~'),'.'),'.'),'.')"/>
<xsl:sort
select="
substring-after(
substring-after(translate(src/domain,'*','~'),'.'),'.')"/>
<xsl:sort
select="substring-after(translate(src/domain,'*','~'),'.')"/>
<xsl:sort select="translate(src/domain,'*','~')" />
<xsl:sort select="src/port" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
输出
<?xml version="1.0" encoding="UTF-8"?>
<?tapia chrome-version='2.0' ?>
<mapGeo>
<a>blah</a>
<b>blah</b>
<maps>
<mapIndividual>
<src>
<scheme>http</scheme>
<domain>d.c.b.a</domain>
<path>somepath</path>
<port>8085</port>
<query>blah</query>
</src>
<tgt>
<domain>r.q.p</domain>
<path>somepath</path>
<query>blah</query>
</tgt>
<x>blah</x>
<y>blah</y>
</mapIndividual>
<mapIndividual>
<src>
<scheme>http</scheme>
<domain>*.c.b.a</domain>
<path>somepath</path>
<port>8085</port>
<query>blah</query>
</src>
<tgt>
<domain>r.q.p</domain>
<path>somepath</path>
<query>blah</query>
</tgt>
<x>blah</x>
<y>blah</y>
</mapIndividual>
<mapIndividual>
<src>
<scheme>tcp</scheme>
<domain>map.google.com</domain>
<port>80</port>
<path>/value</path>
<query>blah</query>
</src>
<tgt>
<scheme>https</scheme>
<domain>map.google.com</domain>
<port>443</port>
<path>/value</path>
<query>blah</query>
</tgt>
<x>blah</x>
<y>blah</y>
</mapIndividual>
<mapIndividual>
<src>
<scheme>https</scheme>
<domain>photos.yahoo.com</domain>
<path>somepath</path>
<query>blah</query>
</src>
<loc>C:\var\tmp</loc>
<x>blah</x>
<y>blah</y>
</mapIndividual>
</maps>
</mapGeo>
请注意:这是在使用.
(点)之前和~
之后(以字母开头)的字母(至少对于美国)这一事实。也可能无法正常扩展...
我支持Martin Honnen comment:在XSLT 2.0中可以更好地解决此问题