在另一个标识的字符串之后查找字符串的第一次出现

时间:2014-01-08 10:07:52

标签: xml xslt

我需要写一个相当复杂的条件。我将在这个例子中解释:

<document>
  <para>
     <wd>Hello</wd>
     <wd>Stackoverflow</wd>
  </para>
  <para>
     <run>
        <wd> PO23135153 </wd>
        <wd> text and numb3rs </wd>
        <wd> 312.000 </wd>
        <wd> moar stuff </wd>
     </run>
     <wd> PO3213213 </wd>
     <wd> blah </wd>
     <wd> 1000.000 </wd>
     <wd> 000.000 </wd>
   </para>
 </document>

我需要做的是选择1000.000和312.000

我相信这可以通过在找到包含“PO *”的字符串后找到包含“.000”的第一个字符串来完成。

XML文档的结构可能会有所不同,PO的实例数量和相关的.000s也是如此

我相信这可以部分地在if表达式中使用“position()”和“contains”来实现,但我不能真正将它们组合在一起。

感谢您的帮助

修改

这更接近于我拥有的XML数据:

   <document>
  <para>
     <wd>Hello</wd>
     <wd>Stackoverflow</wd>
  </para>
  <para>
     <ln>
     <run>
        <wd> PO23135153 </wd>
     </run>
     <run>
        <wd> text and numb3rs </wd>
     </run>
     <run>
        <wd> 312.000 </wd>
     </run>
     <run>
        <wd> moar stuff </wd>
     </ln>
     <ln>
     </abc>
         <wd> PO3213213 </wd>
     </abc>
     <abc>
         <wd> blah </wd>
     </abc>
     <abc>
        <wd> 1000.000 </wd>
     </abc>
     <abc>
        <wd> 000.000 </wd>
     </abc>
     </ln>
   </para>
 </document>

2 个答案:

答案 0 :(得分:0)

这会找到想要的wd元素。如果元素内容中包含“PO”,则它首先匹配wd,并在结果的part_a中输出。然后,这一行:

<xsl:value-of select="following-sibling::wd[contains(.,'.000')][1]"/>

找到第一个以下wd元素,它是一个兄弟,并包含“.000”。限制[1]是必要的,否则在您的示例中也输出“000.000”。

<强>样式表

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

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 <xsl:output method="xml" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="wd[contains(.,'PO')]">
  <result>
     <part_a>
        <xsl:value-of select="."/>
     </part_a>
     <part_b>
        <xsl:value-of select="following-sibling::wd[contains(.,'.000')][1]"/>
     </part_b>
  </result>
 </xsl:template>

 <xsl:template match="wd"/>

</xsl:stylesheet>

<强>输出

<?xml version="1.0" encoding="UTF-8"?>
<result>
  <part_a> PO23135153 </part_a>
  <part_b> 312.000 </part_b>
</result>
<result>
  <part_a> PO3213213 </part_a>
  <part_b> 1000.000 </part_b>
</result>

您的元素包含尾随空格。您可能希望使用normalize-space()在输出中阻止此操作。

修改

更改要求后,这是一种明智的方法。定义一个变量来存储wd,无论它们出现在树中的哪个位置。然后,迭代它们。 @ michael.hor257k 建议的轴的变化。

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

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:variable name="wds" select="//wd"/>

<xsl:template match="/">
  <xsl:for-each select="$wds">
     <xsl:if test="contains(.,'PO')">
        <result>
           <part_a>
              <xsl:value-of select="."/>
           </part_a>
           <part_b>
              <xsl:value-of select="following::wd[contains(.,'.000')][1]"/>
           </part_b>
        </result>
     </xsl:if>
  </xsl:for-each>
</xsl:template>


</xsl:stylesheet>

但首先,您需要更正更新的XML输入,这是无效的。

请注意,这是我最后一次更新此答案。我不愿意花更多的时间在这上面。请清楚说明您的输入XML之前的

答案 1 :(得分:-1)

将问题细分为部分,你就会得到结果。

根据我的理解,您需要的是找到并在第一个<wd>孩子中拥有'PO'并且另一个<wd>孩子拥有'.000'

因此,对于表达式的第一部分:

//*[./wd[position()=1 and contains(text(), 'PO')]]

第二部分:

//*[./wd[contains(text(), '.000')]

不,你必须将两者结合起来:

//*[./wd[contains(text(), '.000')] and ./wd[position()=1 and contains(text(), 'PO')]]

这将返回节点:

/document/para
/document/para/run