2010-11-20 59 views
0

我有一个xml中的术语列表。条款或者有termtype nd或者pt。如果一个术语是termtype nd,它没有ID,而是引用一个termtype PT,它有一个ID。我需要做两件事。xslt查找并插入或用增量编号替换

  1. 用TermType nd的增量编号替换termId值的XXX,所以所有的术语都有一个id。

  2. 其中termType ND引用termType PT,我需要以某种方式寻找其ID,并插入:


<Zthes> 
<term> 
<termName>Term 1</termName> 
<termId>insert new term id N+1 </termId> 
<termType>Nd</termType> 

<relation> 
<relationType>USE</relationType> 
<termId>insert ID of term 2 <termID> 
<termName>Term2</termName> 
</relation> 
</term> 

<term> 
<termName>Term 2</termName> 
<termId>587889</termId> 
<termType>pt</termType> 
</term> 

</zthes> 

任何人都可以给我如何做到这一点的指针。我对xslt一无所知。我在这里找到并找到了关于查找和替换Unique的内容,但从我所了解的答案中,我认为它不适用。

同样,它不一定是xslt。我和一位开发人员合作,他说这是做这件事的最好方式,但答案太微不足道,他不愿意去做。虽然对我来说太困难了!

+0

(1)是“termName”内部“关系”将成为“termName”的精确副本在主术语? (上面有空白区别)(2)对于生成的termId值,它们是从1开始,从文档中的最高termId还是从其他指定值开始? – Erica 2010-11-20 10:27:58

+0

是的,他们将被精确复制,并且termid值可以从1开始。对不起,我应该说清楚。 – Charlie 2010-11-20 10:44:57

回答

0

变换

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:key name="ktermPtIdByName" 
     match="term[termType='pt']/termId" 
     use="../termName"/> 

<xsl:template match="node()|@*"> 
    <xsl:copy> 
     <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="term[termType='Nd']/termId"> 
    <termId> 
    <xsl:number level="single" count="/*/term[termType='Nd']"/> 
    </termId> 
</xsl:template> 

<xsl:template match="relation/termId"> 
    <termId> 
    <xsl:value-of select="key('ktermPtIdByName', ../termName)"/> 
    </termId> 
</xsl:template> 
</xsl:stylesheet> 

当施加在下面的XML文档(您的XML但校正为语法结构良好的和语义正确的,那么放大两次以进行更有趣):

<zthes> 
    <term> 
     <termName>Term 1</termName> 
     <termId></termId> 
     <termType>Nd</termType> 
     <relation> 
      <relationType>USE</relationType> 
      <termId></termId> 
      <termName>Term 2</termName> 
     </relation> 
    </term> 
    <term> 
     <termName>Term 2</termName> 
     <termId>587889</termId> 
     <termType>pt</termType> 
    </term> 
    <term> 
     <termName>Term 3</termName> 
     <termId></termId> 
     <termType>Nd</termType> 
     <relation> 
      <relationType>USE</relationType> 
      <termId></termId> 
      <termName>Term 4</termName> 
     </relation> 
    </term> 
    <term> 
     <termName>Term 4</termName> 
     <termId>587890</termId> 
     <termType>pt</termType> 
    </term> 
</zthes> 

产生想要的,正确的结果

<zthes> 
    <term> 
     <termName>Term 1</termName> 
     <termId>1</termId> 
     <termType>Nd</termType> 
     <relation> 
     <relationType>USE</relationType> 
     <termId>587889</termId> 
     <termName>Term 2</termName> 
     </relation> 
    </term> 
    <term> 
     <termName>Term 2</termName> 
     <termId>587889</termId> 
     <termType>pt</termType> 
    </term> 
    <term> 
     <termName>Term 3</termName> 
     <termId>2</termId> 
     <termType>Nd</termType> 
     <relation> 
     <relationType>USE</relationType> 
     <termId>587890</termId> 
     <termName>Term 4</termName> 
     </relation> 
    </term> 
    <term> 
     <termName>Term 4</termName> 
     <termId>587890</termId> 
     <termType>pt</termType> 
    </term> 
</zthes> 

请注意

  1. 身份规则用于每个节点复制 “原样”。

  2. 模板仅针对需要修改的元素覆盖身份规则。

  3. <xsl:number>用于(我懒)计算所需的termId。

  4. 甲密钥被用于最有效的查找termId由其TermName

+0

这真是太棒了,完美的作品,非常感谢你 – Charlie 2010-11-20 18:39:20

+0

+1非常好的答案。 – 2010-11-20 22:35:46

+0

非常好!是否有办法使它适应,以便它处理引用其他'Nd'术语的'Nd'术语(即,在解决关系之前确保所有'Nd'术语都可以具有有效的ID?) – Erica 2010-11-21 01:16:40

0

我正在阅读一些内容,但我想我知道你在做什么。

我建议用两个单独的XSL来做这件事。将两个XSL传递组合成一个XSL当然是可能的,但实际实现方式因您所使用的XSL库而异(这里有一些细节,如果您好奇:http://www.oreillynet.com/xml/blog/2006/08/multistage_xslt_scripts.html

第一遍应该去通过你所有的条件,并将数字分配给标记为“Nd”的数字。我猜:

(一),一旦他们有一个ID,他们应该有自己的类型变更为“PT”,并

(b)将这些元素的顺序是不特定的。

我建议这样做的一个单独的通道的原因是,你的一个术语可能引用另一个本身是'Nd'类型的术语。如果是这样的话,那么它不会有一个有效的数字来引用(因为没有人会一直尚未分配)

的XSL执行此步骤是这样的:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:template match="term[termType = 'Nd']"> 
     <term> 
      <xsl:copy-of select="termName"/> 
      <termId><xsl:value-of select="position()"/></termId> 
      <termType>pt</termType> 
      <xsl:copy-of select="relation" /> 
     </term> 
    </xsl:template> 

    <xsl:template match="/"> 
     <zthes> 
      <xsl:apply-templates select="zthes/term[termType = 'Nd']"/> 
      <xsl:copy-of select="zthes/term[termType = 'pt']"/> 
     </zthes> 
    </xsl:template> 

</xsl:stylesheet> 

的第二步是获取该变换的输出,并通过第二次变换将其“填充”“关系”项的ID。这是一个相当直接的身份(确切的递归复制)转换,其中有一条特殊规则。特殊规则标识关系节点内的termIds,并根据名称匹配在正确的termId中进行替换。这个变换看起来像这样:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:template match="relation/termId"> 
     <termId> 
      <xsl:value-of select="/zthes/term[termName=current()/../termName]/termId"/> 
     </termId> 
    </xsl:template> 

    <xsl:template match="node()|@*"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*|node()" /> 
     </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 

我希望这会大致做你以后的事情。它不会像你当前的输入数据那样工作,因为你当前的输入实际上是无效的xml。 :)要修复它:

  • 将开始标记 开始标记中的'Zthes'更改为'zthes'。XML区分大小写
  • 在第一个'关系'块中,确保关闭'termId' 节点。目前你打开 两次,而不是关闭它。
  • 在“关系”块的“termName”中,当您的意思是“第2期”时,您引用了“Term2” 。 有一个空格区别, 会阻止它们匹配。

祝你好运!

+0

非常感谢!那真是太好了,我非常感谢你的帮助。 – Charlie 2010-11-20 18:41:00