将新行字符替换为
XSL

发布于 2024-11-07 08:35:30 字数 2876 浏览 2 评论 0原文

我有一个 Sharepoint 列表,我想通过 XSL 数据视图将其转换为 JSON。

我有一个 XSL 递归替换函数,用于替换所有特殊字符(转义反斜杠、双引号 " 等),这为我提供了干净的 JSON,可以在用户浏览器中正确解析。

我需要转义/替换的最后一件事是新行字符。新行会导致某些浏览器中解析 JSON 时出错。

这是一些 xsl,它测试 title 的内容是否有换行符,如果有,我们输出一个段落:

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

<xsl:template match="/">

    <xsl:for-each select="catalog/cd">

        <xsl:if test='contains(title,"&#xA;")'>   
                <p>Found <xsl:value-of select="title" /></p>
        </xsl:if>

    </xsl:for-each>

</xsl:template>
</xsl:stylesheet>

这是一些示例 xml:

<catalog>
    <cd>
        <title>Empire 
Burlesque</title>
        <artist>Bob Dylan</artist>
        <country>USA</country>
        <company>Columbia</company>
        <price>10.90</price>
        <year>1985</year>
    </cd>
    <cd>
        <title>Hide your heart</title>
        <artist>Bonnie Tyler</artist>
        <country>UK</country>
        <company>CBS Records</company>
        <price>9.90</price>
        <year>1988</year>
    </cd>
    <cd>
        <title>Greatest Hits</title>
        <artist>Dolly Parton</artist>
        <country>USA</country>
        <company>RCA</company>
        <price>9.90</price>
        <year>1982</year>
    </cd>
</catalog>

“Empire Burlesque”应该是唯一通过测试的项目,但所有三个标题都通过if 语句 和 被输出。

编辑

修改下面的解决方案,我认为如果我想在单个节点的基础上进行搜索和替换,这应该可行?直到明天我才能在 Sharepoint 中测试它。

<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:template match="/">
  <xsl:for-each select="catalog/cd">

  <xsl:variable name="title_clean">
    <xsl:call-template name="repNL">
      <xsl:with-param name="pText" select="title"/>
    </xsl:call-template>
  </xsl:variable>

  <p><xsl:value-of select='$title_clean' /></p>

  </xsl:for-each>
</xsl:template>


<xsl:template name="repNL">
  <xsl:param name="pText" select="."/>

  <xsl:copy-of select="substring-before(concat($pText,'&#xA;'),'&#xA;')"/>

  <xsl:if test="contains($pText, '&#xA;')">
  <br />
  <xsl:call-template name="repNL">
  <xsl:with-param name="pText" select=
  "substring-after($pText, '&#xA;')"/>
  </xsl:call-template>
  </xsl:if>
</xsl:template>

</xsl:stylesheet>

I have a Sharepoint list which I want to convert to a JSON via an XSL dataview.

I have an XSL recursive replace function which I use to replace all special characters (escape backslash, double quotes to " etc) which gives me nice clean JSON which parses correctly in the users browser.

The final thing that I need to escape / replace is the new line char. The new line causes errors in parsing the JSON in some browsers.

Here is some xsl which tests if the contents of title has a new line char, if it does we output a paragraph:

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

<xsl:template match="/">

    <xsl:for-each select="catalog/cd">

        <xsl:if test='contains(title,"
")'>   
                <p>Found <xsl:value-of select="title" /></p>
        </xsl:if>

    </xsl:for-each>

</xsl:template>
</xsl:stylesheet>

Here is some sample xml:

<catalog>
    <cd>
        <title>Empire 
Burlesque</title>
        <artist>Bob Dylan</artist>
        <country>USA</country>
        <company>Columbia</company>
        <price>10.90</price>
        <year>1985</year>
    </cd>
    <cd>
        <title>Hide your heart</title>
        <artist>Bonnie Tyler</artist>
        <country>UK</country>
        <company>CBS Records</company>
        <price>9.90</price>
        <year>1988</year>
    </cd>
    <cd>
        <title>Greatest Hits</title>
        <artist>Dolly Parton</artist>
        <country>USA</country>
        <company>RCA</company>
        <price>9.90</price>
        <year>1982</year>
    </cd>
</catalog>

"Empire Burlesque" should be the only item to pass the test, but all three titles pass the if statement and are outputted.

EDIT

Modifying the solution below, I assume this should work if I wanted to do the search and replace on a individual node basis? I won't be able to test it in Sharepoint until tomorrow.

<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:template match="/">
  <xsl:for-each select="catalog/cd">

  <xsl:variable name="title_clean">
    <xsl:call-template name="repNL">
      <xsl:with-param name="pText" select="title"/>
    </xsl:call-template>
  </xsl:variable>

  <p><xsl:value-of select='$title_clean' /></p>

  </xsl:for-each>
</xsl:template>


<xsl:template name="repNL">
  <xsl:param name="pText" select="."/>

  <xsl:copy-of select="substring-before(concat($pText,'
'),'
')"/>

  <xsl:if test="contains($pText, '
')">
  <br />
  <xsl:call-template name="repNL">
  <xsl:with-param name="pText" select=
  "substring-after($pText, '
')"/>
  </xsl:call-template>
  </xsl:if>
</xsl:template>

</xsl:stylesheet>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

西瑶 2024-11-14 08:35:30

“帝国滑稽剧”应该是唯一的
通过测试的项目,但所有三个
标题通过 if 语句并且是
输出。

无法重现所声称的问题 - 使用 9 个不同的 XSLT 处理器进行测试,包括所有来自 Microsoft 的处理器。

无论如何:

此转换将文本节点中的任何 NL 字符替换为 br 元素

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

 <xsl:template match="text()" name="repNL">
  <xsl:param name="pText" select="."/>

  <xsl:copy-of select=
  "substring-before(concat($pText,'
'),'
')"/>

  <xsl:if test="contains($pText, '
')">
   <br />
   <xsl:call-template name="repNL">
    <xsl:with-param name="pText" select=
    "substring-after($pText, '
')"/>
   </xsl:call-template>
  </xsl:if>
 </xsl:template>
</xsl:stylesheet>

当应用于以下 XML 文档时(提供的文档带有添加的cd使其更有趣):

<catalog>
    <cd>
        <title>Line1
        Line2
        Line3
        </title>
        <artist>Bob Dylan</artist>
        <country>USA</country>
        <company>Columbia</company>
        <price>10.90</price>
        <year>1985</year>
    </cd>
    <cd>
        <title>Empire
        Burlesque</title>
        <artist>Bob Dylan</artist>
        <country>USA</country>
        <company>Columbia</company>
        <price>10.90</price>
        <year>1985</year>
    </cd>
    <cd>
        <title>Hide your heart</title>
        <artist>Bonnie Tyler</artist>
        <country>UK</country>
        <company>CBS Records</company>
        <price>9.90</price>
        <year>1988</year>
    </cd>
    <cd>
        <title>Greatest Hits</title>
        <artist>Dolly Parton</artist>
        <country>USA</country>
        <company>RCA</company>
        <price>9.90</price>
        <year>1982</year>
    </cd>
</catalog>

产生了想要的正确结果

<catalog>
   <cd>
      <title>Line1<br/>     Line2<br/>      Line3<br/>      
      </title>
      <artist>Bob Dylan</artist>
      <country>USA</country>
      <company>Columbia</company>
      <price>10.90</price>
      <year>1985</year>
   </cd>
   <cd>
      <title>Empire<br/>        Burlesque</title>
      <artist>Bob Dylan</artist>
      <country>USA</country>
      <company>Columbia</company>
      <price>10.90</price>
      <year>1985</year>
   </cd>
   <cd>
      <title>Hide your heart</title>
      <artist>Bonnie Tyler</artist>
      <country>UK</country>
      <company>CBS Records</company>
      <price>9.90</price>
      <year>1988</year>
   </cd>
   <cd>
      <title>Greatest Hits</title>
      <artist>Dolly Parton</artist>
      <country>USA</country>
      <company>RCA</company>
      <price>9.90</price>
      <year>1982</year>
   </cd>
</catalog>

解释

  1. 身份规则/模板副本每个节点“按原样”。

  2. 匹配任何文本节点(也称为“repNL”)的覆盖模板执行以下处理:

  3. < p>使用标记(附加到字符串的 NL 字符),将第一个 NL 字符之前的子字符串(或完整字符串,如果不包含 NL 字符)复制到输出。

  4. 如果确实包含 NL 字符,则会生成 br 元素,模板会递归调用自身以获取该 NL 字符之后的剩余字符串。

"Empire Burlesque" should be the only
item to pass the test, but all three
titles pass the if statement and are
outputted.

Cannot reproduce the alleged problem -- tested with 9 different XSLT processors, including all from Microsoft.

Anyway:

This transformation replaces any NL character in a text node with a br element:

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

 <xsl:template match="text()" name="repNL">
  <xsl:param name="pText" select="."/>

  <xsl:copy-of select=
  "substring-before(concat($pText,'
'),'
')"/>

  <xsl:if test="contains($pText, '
')">
   <br />
   <xsl:call-template name="repNL">
    <xsl:with-param name="pText" select=
    "substring-after($pText, '
')"/>
   </xsl:call-template>
  </xsl:if>
 </xsl:template>
</xsl:stylesheet>

when applied on the following XML document (the provided one with an added cd to make it more interesting):

<catalog>
    <cd>
        <title>Line1
        Line2
        Line3
        </title>
        <artist>Bob Dylan</artist>
        <country>USA</country>
        <company>Columbia</company>
        <price>10.90</price>
        <year>1985</year>
    </cd>
    <cd>
        <title>Empire
        Burlesque</title>
        <artist>Bob Dylan</artist>
        <country>USA</country>
        <company>Columbia</company>
        <price>10.90</price>
        <year>1985</year>
    </cd>
    <cd>
        <title>Hide your heart</title>
        <artist>Bonnie Tyler</artist>
        <country>UK</country>
        <company>CBS Records</company>
        <price>9.90</price>
        <year>1988</year>
    </cd>
    <cd>
        <title>Greatest Hits</title>
        <artist>Dolly Parton</artist>
        <country>USA</country>
        <company>RCA</company>
        <price>9.90</price>
        <year>1982</year>
    </cd>
</catalog>

the wanted, correct result is produced:

<catalog>
   <cd>
      <title>Line1<br/>     Line2<br/>      Line3<br/>      
      </title>
      <artist>Bob Dylan</artist>
      <country>USA</country>
      <company>Columbia</company>
      <price>10.90</price>
      <year>1985</year>
   </cd>
   <cd>
      <title>Empire<br/>        Burlesque</title>
      <artist>Bob Dylan</artist>
      <country>USA</country>
      <company>Columbia</company>
      <price>10.90</price>
      <year>1985</year>
   </cd>
   <cd>
      <title>Hide your heart</title>
      <artist>Bonnie Tyler</artist>
      <country>UK</country>
      <company>CBS Records</company>
      <price>9.90</price>
      <year>1988</year>
   </cd>
   <cd>
      <title>Greatest Hits</title>
      <artist>Dolly Parton</artist>
      <country>USA</country>
      <company>RCA</company>
      <price>9.90</price>
      <year>1982</year>
   </cd>
</catalog>

Explanation:

  1. The identity rule/template copies every node "as-is".

  2. The overriding template that matches any text node (also named as "repNL") prforms the following processing:

  3. Using a sentinel (a NL character appended to the string), the substring before the first NL character (or the complete string, if th no NL character is contained) is copied to the output.

  4. If a NL character is really contained, then a br element is generated and the template calls itself recursively for the remaining string after this NL character.

ヤ经典坏疍 2024-11-14 08:35:30

如果您使用XslCompiledTransform(C#),我相信您在使用以下API来转换XML时会遇到这个问题:
XslCompiledTransform.Transform(XmlReader input, XmlWriter results)

但是,以下 API 运行良好:
XslCompiledTransform.Transform(字符串,字符串);

这是有线的,但我不明白为什么......

If you are using XslCompiledTransform(C#), I believe you will encounter the issue if you use below API to transform the XML:
XslCompiledTransform.Transform(XmlReader input, XmlWriter results)

However, below API works well:
XslCompiledTransform.Transform(string, string);

This is wired, but I don't figure out why...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文