[XSLT难题 No.5][200分]

CrazyJavar 2003-08-22 04:48:22
这个帖子给200分,因为我等级不够,等解决后我再开一个帖子,补上另外的100分,谢谢

一。需求
1.给定一个字符串变量,例如"_en"
2.找到源文档中的<Spec>元素,递归扫描<Spec>为根节点的子文档树,找到所有名称结尾是"_en"的属性,例如"abc_en","def_en"等等
3.搜索找到的属性例如"abc_en"所在的元素,判断其是否含有名为"abc"(也就是"abc_en" substring "_en" = "abc")的属性
4.如果存在"abc"属性,那么交换"abc"属性和"abc_en"属性的值
5.如果不存在,那么和文档中的其它内容一样,原封不动copy到目的文档
6.总的来说,就是要交换第2.3.4步中符合条件的属性值,其余的不动,生成目的文档

二。源xml文档
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- edited with XMLSPY v5 U (http://www.xmlspy.com) by a (a) -->
<ObjectPersistSpace>
<Spec key="c" oemId="EGFM28" oemName="EGFM28" policy="manage" mem="中文" mem_en="English">
<sub>
<SHRSpecSub key="p" lim="9">
<lst>
<SHRSpecSubVal ins="fixed" spec="FEWPort" value="1"/>
<SHRSpecSubVal ins="fixed" spec="FEWPort" value="2"/>
<SHRSpecSubVal ins="fixed" spec="FEWPort" value="3"/>
<SHRSpecSubVal ins="fixed" spec="FEWPort" value="4"/>
<SHRSpecSubVal ins="fixed" spec="FEWPort" value="5"/>
<SHRSpecSubVal ins="fixed" spec="FEWPort" value="6"/>
<SHRSpecSubVal ins="fixed" spec="FEWPort" value="7"/>
<SHRSpecSubVal ins="fixed" spec="FEWPort" value="8"/>
</lst>
</SHRSpecSub>
<SHRSpecSub key="c" lim="3">
<lst>
<SHRSpecSubVal ins="fixed" spec="CFE08" value="1"/>
<SHRSpecSubVal ins="fixed" spec="CGE02" value="2"/>
</lst>
</SHRSpecSub>
</sub>
<fprp>
<SHRSpecFPrp fprp="feCfg" disp="积分软卧耳机哦我" disp_en="enjsdofuwoer" mem="殴打开发公平" mem_en="ejrlfenldfo">
<val teid="Boolean" val="true"/>
</SHRSpecFPrp>
</fprp>
<mprp>
<SHRSpecMPrp mprp="verInfo" disp="中文使得玩儿据我" disp_en="englishsdfjoweuru" mem="" mem_en="" mode="RO" teid="HRVerInfo_Seq"/>
</mprp>
<cprp/>
<alm>
<SHRSpecAlm id="9" src="" _id="ChssOffLine"/>
<SHRSpecAlm id="67" src="" _id="ChssFault"/>
</alm>
<per/>
<view icon="card_i.gif" map="" photo=""/>
</Spec>
</ObjectPersistSpace>


三。xslt文档。我自己写了一个,但跑起来后有问题,仅仅把所有属性copy过来了,请教一下高手,该如何修改呢,并说说我错在哪里,谢谢
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- out format -->
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<!-- language variable, e.g. "_en" -->
<xsl:variable name="language">_en</xsl:variable>
<!-- top template -->
<xsl:template match="/">
<xsl:apply-templates select="node()"/>
</xsl:template>
<!-- recurse template for scanning nodes-->
<xsl:template match="node()">
<!-- scan attributes -->
<xsl:for-each select="@*">
<!-- suffix variable -->
<xsl:variable name="suffix">
<xsl:value-of select="substring(name(), string-length(name()) - string-length($language) + 1, string-length(name()))"/>
</xsl:variable>
<!-- prefix variable -->
<xsl:variable name="prefix">
<xsl:value-of select="substring(name(), 0, string-length(name()) - string-length($language) + 1)"/>
</xsl:variable>
<!-- If being a attribute which name's ending contains language variable -->
<xsl:choose>
<xsl:when test="$suffix = $language">
<xsl:choose>
<xsl:when test="../@*[name() = $prefix]">
<xsl:call-template name="TransformTemplate">
<xsl:with-param name="defaultContent">
<xsl:value-of select="$prefix"/>
</xsl:with-param>
<xsl:with-param name="languageContent">
<xsl:value-of select="concat($prefix, $suffix)"/>
</xsl:with-param>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="CopyTemplate"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
</xsl:choose>
</xsl:for-each>
<xsl:apply-templates select="node()"/>
</xsl:template>
<!-- element copy template -->
<xsl:template name="CopyTemplate">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
<!-- element transform template -->
<xsl:template name="TransformTemplate">
<xsl:param name="defaultContent"/>
<xsl:param name="languageContent"/>
<xsl:variable name="temp">
<xsl:value-of select="../@*[name()=$languageContent]"/>
</xsl:variable>
<xsl:copy>
<xsl:copy-of select="../@*[name() != $defaultContent and name() != $languageContent]"/>
<xsl:attribute name="{$languageContent}"><xsl:value-of select="../@*[name()=$defaultContent]"/></xsl:attribute>
<xsl:attribute name="{$defaultContent}"><xsl:value-of select="$temp"/></xsl:attribute>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
...全文
48 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
CrazyJavar 2003-08-30
  • 打赏
  • 举报
回复
谢谢两位了,前两天不能来上网,所以结帖晚了,见谅见谅
月光易水 2003-08-25
  • 打赏
  • 举报
回复
why?
xml结构不允许一个节点有两个相同属性的

wind2000+ie6 正常


:_)
CrazyJavar 2003-08-25
  • 打赏
  • 举报
回复
方案一测试的时候

结果文档中发现会出现两个mem_en属性
月光易水 2003-08-25
  • 打赏
  • 举报
回复
方案1问题所在?

方案2亦可

不过方案1如将模板TransformTemplate 去掉,直接在模板node()中进行属性赋值
则两者区别:
方案1: 则在每个@*循环中,利用sort排序,读取一次 xpath: @*[name() = '***']
方案2: 则在每个@*循环中,不是用排序,读取两次次 xpath: @*[name() = '***']


:_)
surfw3 2003-08-25
  • 打赏
  • 举报
回复
将后缀作变量,OK!
月光易水 2003-08-25
  • 打赏
  • 举报
回复
呵呵,是的

上贴中 ‘2. 上面的说错了。不过比较方案1、2’

是指上上贴中
'则两者区别:方案1: ...... 方案2: ......'

没说清楚,让你误解了,不好意思


:_)
surfw3 2003-08-25
  • 打赏
  • 举报
回复
moonpiazza(月下小生),你好

关于第一点"测试'A and B'判断时,如果A为假时,不会再去测B的真假",我也仅是猜测,无资料可查。
在《ASP与XML高级编程》一书中提到XSL查询机制是基于优化的C++实现方案,所以我想MSXML不会在A假时仍去测B的真假吧?
月光易水 2003-08-25
  • 打赏
  • 举报
回复
to:surfw3
1. 测试"A and B"判断时,如果A为假时,不会再去测B的真假
2. 上面的说错了。不过比较方案1、2

在每个@*循环
方案2.
下列判断皆使用判断使用(@*[...])
如果节点属性不符合预定的条件,则判断中,第二个判断一定执行
否则,如果有一组(@**_en,@**)符合条件,必判断两次(一个节点一次)
否则,判断一次

方案1
只有当当节点符合条件(@**_en)时,两次使用xpath(@*[...])
其他节点(包括@**),在循环中只是读取节点属性
比方案2多的步骤:
1. 使用xsl:sort进行排序
2. 重复给节点属性(@**)赋值一次

声明:上面只是在实现的基础上讨论结构的优化,在不了解xslt底层机制的情况下,小生也不敢断言那种方法效率较高

to: CrazyJavar
如果 '_en'不作为变量,可以使用xsl:key的特性来进行解析,也可作为方法之一。


:_)
surfw3 2003-08-25
  • 打赏
  • 举报
回复
1.在作"A and B"判断时,如果A为假时,应该不会再去测B的真假,但不知MSXML是怎么做的。
2.基于1的假设,方案二在每个@*循环中:
如果属性名的后缀不是$language,就不会去遍历第一个xsl:when中的../@*
如果属性名的后缀是$language,且满足条件时,则遍历第一个xsl:when中的../@*
如果属性名的后缀是$language,且不满足条件时,才会遍历二个xsl:when中的../@*


我测试方案一也没问题的。
CrazyJavar 2003-08-24
  • 打赏
  • 举报
回复
谢谢楼上两位的指点

我先看看

看懂后如果OK

马上结帖

谢谢
CrazyJavar 2003-08-24
  • 打赏
  • 举报
回复
第一位朋友提供的解答有点问题

第二位的我稍做修改后如下

<?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" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:variable name="language">_jpn</xsl:variable>
<xsl:template match="node()">
<xsl:copy>
<xsl:for-each select="@*">
<xsl:variable name="suffix">
<xsl:value-of select="substring(name(),string-length(name())-(string-length($language) - 1))"/>
</xsl:variable>
<xsl:variable name="prefix">
<xsl:value-of select="substring(name(),1,string-length(name())-string-length($language))"/>
</xsl:variable>
<xsl:variable name="currentname">
<xsl:value-of select="name()"/>
</xsl:variable>
<xsl:choose>
<xsl:when test="$suffix=$language and ../@*[name()=$prefix]">
<xsl:attribute name="{$prefix}"><xsl:value-of select="."/></xsl:attribute>
</xsl:when>
<xsl:when test="../@*[name()=concat($currentname,$language)]">
<xsl:attribute name="{concat($currentname,$language)}"><xsl:value-of select="."/></xsl:attribute>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
surfw3 2003-08-24
  • 打赏
  • 举报
回复
上面写错了

第一个xsl:when
<xsl:when test="../@*[name()=$prefix]">
应改为
<xsl:when test="$suffix='_en' and ../@*[name()=$prefix]">
surfw3 2003-08-23
  • 打赏
  • 举报
回复
sry:

第一个xsl:when
<xsl:when test="../@*[name()=$prefix]">
改为
<xsl:when test="../@*[name()=$prefix and $suffix='_en']">
surfw3 2003-08-23
  • 打赏
  • 举报
回复
修改xsl文档
1.xsl转换时,源xml树是不动的,所以在交换两属性值时,转换时将一值放入另一属性中就可以了。
2.选择node时对路径作了一下变动。

<?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" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:template match="node()">

<xsl:copy>

<xsl:for-each select="@*">

<xsl:variable name="suffix">
<xsl:value-of select="substring(name(),string-length(name())-2)"/>
</xsl:variable>
<xsl:variable name="prefix">
<xsl:value-of select="substring(name(),1,string-length(name())-3)"/>
</xsl:variable>
<xsl:variable name="currentname">
<xsl:value-of select="name()"/>
</xsl:variable>

<xsl:choose>
<xsl:when test="../@*[name()=$prefix]">
<xsl:attribute name="{$prefix}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:when>
<xsl:when test="../@*[name()=concat($currentname,'_en')]">
<xsl:attribute name="{concat($currentname,'_en')}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="."/>
</xsl:otherwise>
</xsl:choose>

</xsl:for-each>
<xsl:apply-templates select="node()"/>

</xsl:copy>

</xsl:template>

</xsl:stylesheet>
月光易水 2003-08-22
  • 打赏
  • 举报
回复
不能正确解析原因: 对同一属性多次赋值

两个模板(CopyTemplate,TransformTemplate)每次都重写了当前节点的所有属性


解决方法:
a. 循环读取属性,并以属性名称顺序读取数据
b. 如节点属性符合条件,则给节点属性(@***_en)及相关节点属性(@***)赋值,不符合条件的节点属性直接拷贝
c. 只有相关节点属性(@***)会被被赋值两次,前面一次赋值无效(当前了 :) ,其他节点属性只赋值一次

因为以属性名称顺序读取数据,即使xml结构中节点属性(@***)在符合条件的节点属性(@***_en)之后,也可以正确进行解析

try:

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- out format -->
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<!-- language variable, e.g. "_en" -->
<xsl:variable name="language">_en</xsl:variable>
<!-- top template -->

<!-- recurse template for scanning nodes-->
<xsl:template match="node()">
<xsl:copy>
<!-- scan attributes -->
<xsl:for-each select="@*">
<xsl:sort select="name()" data-type="text" order="ascending" />
<!-- suffix variable -->
<xsl:variable name="suffix">
<xsl:value-of select="substring(name(), string-length(name()) - string-length($language) + 1, string-length(name()))"/>
</xsl:variable>
<!-- prefix variable -->
<xsl:variable name="prefix">
<xsl:value-of select="substring(name(), 0, string-length(name()) - string-length($language) + 1)"/>
</xsl:variable>
<!-- If being a attribute which name's ending contains language variable -->
<xsl:choose>
<xsl:when test="$suffix = $language">
<xsl:choose>
<xsl:when test="../@*[name() = $prefix]">

<xsl:call-template name="TransformTemplate">

<xsl:with-param name="defaultContent">
<xsl:value-of select="$prefix"/>
</xsl:with-param>
<xsl:with-param name="languageContent">
<xsl:value-of select="concat($prefix, $suffix)"/>
</xsl:with-param>

<xsl:with-param name="defaultVal">
<xsl:value-of select="../@*[name() = $prefix]"/>
</xsl:with-param>
<xsl:with-param name="languageVal">
<xsl:value-of select="."/>
</xsl:with-param>

</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<!-- element copy -->
<xsl:copy-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<!-- element copy -->
<xsl:copy-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>

<!-- element transform template -->
<xsl:template name="TransformTemplate">
<xsl:param name="defaultContent"/>
<xsl:param name="languageContent"/>
<xsl:param name="defaultVal"/>
<xsl:param name="languageVal"/>

<xsl:attribute name="{$defaultContent}"><xsl:value-of select="$languageVal"/></xsl:attribute>
<xsl:attribute name="{$languageContent}"><xsl:value-of select="$defaultVal"/></xsl:attribute>

</xsl:template>

</xsl:stylesheet>


:_)

8,906

社区成员

发帖
与我相关
我的任务
社区描述
XML/XSL相关问题讨论专区
社区管理员
  • XML/XSL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧