XSLT - 从cdata获取排序信息

时间:2013-08-29 10:39:03

标签: xslt xslt-1.0

我是xslt主题的新手,有一个我自己无法解决的问题。 这是我的xml文件的示例:

<node>
  <failure><![CDATA[
    some useless information.
    CRS urn:ogc:def:crs:EPSG::25830 not defined.
    CRS urn:ogc:def:crs:EPSG::25833 not possible.
    CRS urn:ogc:def:crs:EPSG::25830 not defined. 
    some useless information.]]>
  </failure>
</node>

主要问题是信息站在CDATA块中,并且混合了许多不同的信息。我找到了一种方法来解决它们,但只是作为一个字符串值无法区分排序。

我需要一种方法来提取符合模式的元素:“CRS [-unknown-] [id]而不是[result]”

我想要的是这样的:

<failure>
    <CRS>
      <id> urn:ogc:def:crs:EPSG::25830 </id>
      <result> not defined </result>
    </CRS>
    <CRS>
      <id> urn:ogc:def:crs:EPSG::25833 </id>
      <result> not posible </result>
    </CRS>
    <CRS>
      <id> urn:ogc:def:crs:EPSG::25830 </id>
      <result> not defined </result>
    </CRS>
</failure>

有人可以帮助我或者解决类似问题吗?

1 个答案:

答案 0 :(得分:0)

XSLT 2.0具有xsl:analyze-string,专为此任务而设计,因此,如果可能,我建议您升级到2.0处理器,例如Saxon

<xsl:template match="node">
  <failure>
    <xsl:analyze-string select="failure"
         regex="^\s*CRS\s*(\S+)\s*(not\s*.*)$" flags="m">
      <xsl:matching-substring>
        <CRS>
          <id><xsl:value-of select="regex-group(1)" /></id>
          <result><xsl:value-of select="normalize-space(regex-group(2))" /></result>
        </CRS>
      </xsl:matching-substring>
    </xsl:analyze-string>
  </failure>
</xsl:template>

XSLT 1.0中的字符串操作工具相比之下非常有限,并且由于XSLT是一种没有可更新变量的函数式语言,因此您必须编写某种可靠的递归call-template逻辑来分割文本分成几行,然后使用substring-beforesubstring-after依次从每行中提取相关位。

<xsl:template name="each-line">
  <xsl:param name="val" />
  <!-- pull out everything before the first newline and normalize (trim leading
       and trailing whitespace and squash internal whitespace to a single space
       character -->
  <xsl:variable name="firstLine"
    select="normalize-space(substring-before($val, '&#10;'))" />
  <!-- pull out everything after the first newline -->
  <xsl:variable name="rest" select="substring-after($val, '&#10;')" />
  <xsl:if test="$firstLine">
    <xsl:call-template name="process-line">
      <xsl:with-param name="line" select="$firstLine" />
    </xsl:call-template>
  </xsl:if>
  <!-- if there are still some non-empty lines left then process them recursively -->
  <xsl:if test="normalize-space($rest)">
    <xsl:call-template name="each-line">
      <xsl:with-param name="val" select="$rest" />
    </xsl:call-template>
  </xsl:if>
</xsl:template>

<xsl:template name="process-line">
  <xsl:param name="line" />
  <xsl:if test="starts-with($line, 'CRS ') and contains($line, ' not ')">
    <!-- here $line will be something like
         "CRS urn:ogc:def:crs:EPSG::25830 not defined." -->
    <CRS>
      <!-- ID is everything between the first and second spaces -->
      <id><xsl:value-of select="substring-before(substring-after($line, ' '), ' ')" /></id>
      <!-- result is everything after the second space -->
      <result><xsl:value-of select="substring-after(substring-after($line, ' '), ' ')" /></result>
    </CRS>
  </xsl:if>
</xsl:template>

您可以使用类似

的构造来调用此逻辑
<xsl:template match="node">
  <failure>
    <xsl:call-template name="each-line">
      <xsl:with-param name="val" select="failure" />
    </xsl:call-template>
  </failure>
</xsl:template>