使用xslt提取cdata

时间:2010-09-14 10:34:43

标签: xslt

以下是具有CDATA部分的

<?xml version="1.0" encoding="ISO-8859-1"?>
<character>
<name>
<role>Indiana Jones</role>
<actor>Harrison Ford</actor>
<part>protagonist</part>
<![CDATA[  <film>Indiana Jones and the Kingdom of the Crystal Skull</film>]]>
</name>
</character>

对于上面的xml我需要撕掉CDATA并在现有元素“film”下添加新元素,所以最终的输出将是:

<?xml version="1.0" encoding="ISO-8859-1"?>
<character>
<name>
<role>Indiana Jones</role>
<actor>Harrison Ford</actor>
<part>protagonist</part>
<film>Indiana Jones and the Kingdom of the Crystal Skull</film>
<Language>English</Language>
</name>
</character>

这可以使用XSLT完成吗?

5 个答案:

答案 0 :(得分:3)

略微修改的识别功能应该有效。

鉴于此XML:

<?xml version="1.0" encoding="ISO-8859-1"?>
<character>
    <name>
        <role>Indiana Jones</role>
        <actor>Harrison Ford</actor>
        <part>protagonist</part>
        <![CDATA[  <film>Indiana Jones and the Kingdom of the Crystal Skull</film>]]>
    </name>
</character>

使用此XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">

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

    <xsl:template match="*">
        <xsl:copy>
            <xsl:apply-templates select="*" />
            <xsl:value-of select="text()" disable-output-escaping="yes"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

会产生此输出:

<?xml version="1.0" encoding="UTF-8"?>
<character>
   <name>
      <role>Indiana Jones</role>
      <actor>Harrison Ford</actor>
      <part>protagonist</part>
          <film>Indiana Jones and the Kingdom of the Crystal Skull</film>
    </name>
</character>

(使用Saxon-HE 9.3.0.5在oXygen 12.2中测试。)

答案 1 :(得分:2)

由于CDATA块中的film元素似乎格式正确,因此可以使用disable-output-escaping。如果匹配名称/文本(),请选择带有DOE的value-of,然后立即插入Language元素。

<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"  />

<!--Identity template simply copies content forward -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>


<xsl:template match="name/text()">
    <!--disable-output-escaping will prevent the "film" element from being escaped.
    Since it appears to be well-formed you should be safe, but no guarentees -->
    <xsl:value-of select="." disable-output-escaping="yes" />
    <Language>English</Language>
</xsl:template>

</xsl:stylesheet>

答案 2 :(得分:1)

解决此问题的另一种方法是使用Andrew Welsh LexEv XMLReader来进一步控制转换。这使您可以将CDATA部分作为标记处理。

答案 3 :(得分:0)

首先,您的输入XML具有“CDATA”的事实在某种意义上是无关紧要的...... XSLT无法判断它是否是CDATA。您的输入XML的关键在于您已转义标记<film>...</film>,并且您希望将其转换为真实元素。

如果您知道转义元素将始终具有特定名称(“电影”),并且您知道它发生的位置,则可以将其剥离并轻松替换:

   <xsl:template match="text()[contains(., '&lt;film>')]">
      <film>
         <xsl:value-of select="substring-before(substring-after(., '&lt;film>'),
              '&lt;/film>')"/>
      </film>
   </xsl:template>

如果您事先不知道转发标记的位置以及元素名称,您可以使用XSLT 2.0的<xsl:analyze-string>来查找和替换它们。但正如Alejandro指出的那样,使用正则表达式对XML进行一般解析会变得非常混乱。只有你知道标记很简单才有可能。

答案 4 :(得分:0)

我正在处理类似的事情,我找到了一个很好的解决方案,所以我想与你分享,但这个是NSXMLParser

如果您使用NSXMLParser,则会有一个名为foundCDATA的委托方法,如下所示:

- (void)parser:(NSXMLParser *)parser foundCDATA:(NSData *)CDATABlock{
    if (!parseElement) {
        return;
    }
    if (parsedElementData==nil) {
        parsedElementData = [[NSMutableData alloc] init];
    }
    [parsedElementData appendData:CDATABlock];

    //Grabs the whole content in CDATABlock.
    NSMutableString *content = [[NSMutableString alloc] initWithData:CDATABlock encoding:NSUTF8StringEncoding];

 }

现在将this prewritten class添加到您的项目中。然后将其导入要在其中使用的解析器类:

#import NSString_stripHTML

现在,您可以将以下行添加到foundCDATA方法:

NSString *strippedContent;
strippedContent = [content strippedHtml];

现在您将删除没有任何额外字符的剥离文本。你可以从这个剥离的文本中对你想要的任何内容进行子串。