【问题标题】:How do I serialize output from a node-set in xslt 1.0?如何序列化 xslt 1.0 中节点集的输出?
【发布时间】:2019-03-22 15:35:43
【问题描述】:

我正在使用 XSLT 中的一些 XML。我想将其中的一部分保存在内容节点中。我将 CDATA 节点排除在此示例之外。

当我像这样抓取 xml 时,它被转义了,即。 < =

<content name="test”>
      <xsl:copy-of select="//content[@name='something']/node()" />
</content>

但是在将数据存储到内容节点之前,我需要对数据进行一些处理。我有一个 xsl:for-each 调用,它循环保存部分。但是,当我调用类似的命令时,我无法让 XML 转义。

<xsl:for-each select="exsl:node-set($xml)//data">
    <content name="test">
              <xsl:copy-of select="./node()" />
    </content>

我已经在它周围放置了 CDATA 节点并输出了内容,但是我在系统中遇到了双重转义问题。我真的需要这个调用副本来输出转义的 XML。

我真的想要这样的东西:

<content name="test">
          &lt;data&gt;Some data&lt;\data&gt;
        </content>

输入会是这样的:

<root>
<data>Some data</data>
<data>more data</data>
</root>

这是对数据的简化。数据节点中会有额外的 xml 节点。

【问题讨论】:

  • 当涉及到 CDATA 和“转义的 XML”时,最好显示输入/样式表/所需的输出,因为人们倾向于在这个主题中引用非常不同的东西。
  • 已更新。我真的只是希望特殊字符转义。 "
  • 你有什么意见?
  • 看起来您正在对一个文档片段进行字符串化,以供另一个不理解 XML 的应用程序使用。没有输入源就很难分辨。我的建议是从链中删除有问题的应用程序。
  • 我输入了一些模拟输入。我认为这与对 exsl:node-set($xml) 的调用有关

标签: xml xslt


【解决方案1】:

Evan Lenz 在http://lenzconsulting.com/xml-to-string/ 有一个基于 XSLT 1 的 XML 序列化实现:如果你使用它,你就有了,例如

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

  <xsl:import href="http://lenzconsulting.com/xml-to-string/xml-to-string.xsl"/>

  <xsl:output indent="yes" cdata-section-elements="content"/>

  <xsl:template match="/">
      <xsl:apply-templates/>
  </xsl:template>

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

  <xsl:template match="data">
      <content>
          <xsl:apply-templates select="." mode="xml-to-string"/>
      </content>      
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/pPzifpn/4

如果处理器是 libxslt,那么它可能允许您实现扩展函数,例如 PHP 允许您调用 PHP 函数,并且 PHP 中的 DOMDocument 有一个要序列化的 saveXML 函数,因此您可以从XSLT:

<?php

function serializeNode($node) {
  return $node[0]->ownerDocument->saveXML($node[0]);
}

$xml = <<<EOT
<root>
<data>Some data</data>
<data>more data</data>
</root>
EOT;

$xsl = <<<EOT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:php="http://php.net/xsl"
    exclude-result-prefixes="php"
    version="1.0">

  <xsl:output indent="yes" cdata-section-elements="content"/>

  <xsl:template match="/">
      <xsl:apply-templates/>
  </xsl:template>

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

  <xsl:template match="data">
      <content>
          <xsl:value-of select="php:function('serializeNode', .)"/>
      </content>      
  </xsl:template>

</xsl:stylesheet>
EOT;

$doc = new DOMDocument();
$doc->loadXML($xml);

$proc = new XSLTProcessor();
$proc->registerPHPFunctions('serializeNode');

$sheet = new DOMDocument();
$sheet->loadXML($xsl);

$proc->importStylesheet($sheet);

echo $proc->transformToXml($doc);

?>

【讨论】:

  • 我很欣赏这个答案,但根据我的要求,使用来自第 3 方的代码对我来说很复杂。
  • 使用来自 StackOverflow 答案的代码不会使用来自第 3 方的代码吗?不管怎样,试着找出处理器/环境是否有任何扩展函数来解决这个问题,或者很容易让你编写一个执行序列化的函数。
  • 来自 Evan Lenz 版权声明:Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:... 保留、复制该声明,不要对 Evan 背书提出任何主张
【解决方案2】:
<!-- XSL 1.0 -->
<xsl:template match="*|@*|text()|comment()" mode="copy">
    <xsl:param name="_-"><!--<">-do-not-modify-this--></xsl:param>
    <xsl:variable name="ch" select="document('')//*[@name='_-']/comment()"/>
    <xsl:variable name="lt" select="substring($ch, 1, 1)"/>
    <xsl:variable name="qq" select="substring($ch, 2, 1)"/>
    <xsl:variable name="gt" select="substring($ch, 3, 1)"/>
    <xsl:choose>
        <xsl:when test="self::*">
            <xsl:value-of select="concat($lt, name())"/>
            <xsl:apply-templates select="@*" mode="copy"/>
            <xsl:variable name="ns" select="namespace-uri()"/>
            <xsl:if test="$ns and not(ancestor::*[namespace-uri() = $ns])">
                <xsl:variable name="pf" select="substring-before(name(), ':')"/>
                <xsl:value-of select="concat(' xmlns:', $pf, '=', $qq, $ns, $qq)"/>
            </xsl:if>
            <xsl:value-of select="$gt"/>
            <xsl:apply-templates select="*|text()|comment()" mode="copy"/>
            <xsl:value-of select="concat($lt, '/', name(), $gt)"/>
        </xsl:when>
        <xsl:when test="self::comment()">
            <xsl:value-of select="concat($lt, '!--', ., '--', $gt)"/>
        </xsl:when>
        <xsl:when test="self::text()"><xsl:value-of select="."/></xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="concat(' ', name(), '=', $qq, ., $qq)"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

【讨论】:

    猜你喜欢
    • 2016-07-03
    • 2013-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多