[英]XSLT: How to transform partially escaped XML with XSLT 1.0 and XALAN processor?
我有這個:
<root>
<row>
<field>&lt;![CDATA[&lt;comprobante xmlns:xsi="http://www.w3.org/2001/XMLSchema"&gt;
&lt;inicioCFD&gt;
&lt;idArchivo&gt;182NAI053402&lt;/idArchivo&gt;
&lt;etiquetaCFD&gt;NCR&lt;/etiquetaCFD&gt;
&lt;/inicioCFD&gt;
&lt;/comprobante&gt;]]&gt;</field>
</row>
</root>
我需要這個:
<comprobante>
<idArchivo etiquetaCFD="NCR">182NAI053402</idArchivo>
</comprobante>
我正在使用這個xslt:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
xmlns:a="http://www.tralix.com/cfd/2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema"
xmlns:xalan="http://xml.apache.org/xalan"
extension-element-prefixes="exsl xalan">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:template match="/root/row/field">
<xsl:variable name="comprobante_">
<xsl:variable name="p6">
<xsl:variable name="p5">
<xsl:variable name="p4">
<xsl:variable name="p3">
<xsl:variable name="p2">
<xsl:variable name="p1">
<xsl:value-of select="substring-before(substring-after(.,'CDATA['),']]')"/>
</xsl:variable>
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="$p1"/>
<xsl:with-param name="replace" select="'gt;'" />
<xsl:with-param name="with" select="'¬'"/>
</xsl:call-template>
</xsl:variable>
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="$p2"/>
<xsl:with-param name="replace" select="'lt;'"/>
<xsl:with-param name="with" select="'~'"/>
</xsl:call-template>
</xsl:variable>
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="$p3"/>
<xsl:with-param name="replace" select="'&~'"/>
<xsl:with-param name="with" select="'<'"/>
</xsl:call-template>
</xsl:variable>
<xsl:call-template name="replace-string">
<xsl:with-param name="text" select="$p4"/>
<xsl:with-param name="replace" select="'&¬'"/>
<xsl:with-param name="with" select="'>'"/>
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="$p5" disable-output-escaping="yes"/>
</xsl:variable>
<xsl:copy-of select="xalan:nodeset($p6)"/>
</xsl:variable>
<xsl:variable name="comprobante" select="xalan:nodeset($comprobante_)"/>
<comprobante>
<idArchivo>
<xsl:attribute name="etiquetaCFD">
<xsl:value-of select="$comprobante/comprobante/inicioCFD/etiquetaCFD"/>
</xsl:attribute>
<xsl:value-of select="$comprobante/comprobante/inicioCFD/idArchivo"/>
</idArchivo>
</comprobante>
</xsl:template>
<xsl:template name="replace-string">
<xsl:param name="text"/>
<xsl:param name="replace"/>
<xsl:param name="with"/>
<xsl:choose>
<xsl:when test="contains($text,$replace)">
<xsl:value-of select="substring-before($text,$replace)"/>
<xsl:value-of select="$with"/>
<xsl:call-template name="replace-string">
<xsl:with-param name="text"
select="substring-after($text,$replace)"/>
<xsl:with-param name="replace" select="$replace"/>
<xsl:with-param name="with" select="$with"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
它產生了這個:
<comprobante>
<idArchivo etiquetaCFD=""></idArchivo>
</comprobante>
引起空值是因為轉義的XML不是像XSLT那樣的XML :如何轉換部分轉義的XML? 說,所以我無法從我的$ comprobante變量中讀取任何內容。
但在那篇文章中,迪米特里說它可以用saxon:parse()。 好吧,我正在使用Xalan處理器,但我找不到類似的東西。 我只能使用xalan和xslt 1.0。
有幫助嗎?
提前致謝
這樣的東西會從field
內部提取轉義的內容,並將其作為純文本輸出(恰好是格式良好的XML):
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" />
<xsl:template match="/">
<xsl:variable name="withoutCDataStart"
select="substring(root/row/field, 13)" />
<xsl:variable name="withoutCDataEnd"
select="substring($withoutCDataStart, 1,
string-length($withoutCDataStart) - 6)" />
<xsl:call-template name="unescape">
<xsl:with-param name="text" select="$withoutCDataEnd" />
</xsl:call-template>
</xsl:template>
<xsl:template name="unescape">
<xsl:param name="text" />
<xsl:choose>
<xsl:when test="contains($text, '&')">
<xsl:value-of select="substring-before($text, '&')" />
<xsl:variable name="afterAmp" select="substring-after($text, '&')" />
<xsl:choose>
<xsl:when test="starts-with($afterAmp, 'amp;')">&</xsl:when>
<xsl:when test="starts-with($afterAmp, 'lt;')"><</xsl:when>
<xsl:when test="starts-with($afterAmp, 'gt;')">></xsl:when>
<xsl:when test="starts-with($afterAmp, 'quot;')">"</xsl:when>
<xsl:when test="starts-with($afterAmp, 'apos;')">'</xsl:when>
</xsl:choose>
<xsl:call-template name="unescape">
<xsl:with-param name="text" select="substring-after($afterAmp, ';')" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
然后,您必須將此輸出反饋到另一個樣式表,以進行所需的實際轉換。
@IanRoberts,@ MichaelKay,在你的幫助下,我想出了如何創建一個轉義的xml解析器,這個工作的xslt就是結果。 謝謝你的幫助!
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl"
xmlns:xsi="http://www.w3.org/2001/XMLSchema">
<xsl:output indent="yes"/>
<xsl:template match="/">
<xsl:variable name="withoutCDataStart"
select="substring-after(root/row/field, '&lt;![CDATA[')"/>
<xsl:variable name="withoutCDataEnd"
select="substring-before($withoutCDataStart, ']]&gt;')"/>
<xsl:variable name="unEscapedXml">
<xsl:call-template name="unescape">
<xsl:with-param name="text" select="$withoutCDataEnd"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="parsedXml_">
<xsl:call-template name="parseXml">
<xsl:with-param name="text" select="$unEscapedXml"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="parsedXml" select="exsl:node-set($parsedXml_)"/>
<comprobante>
<idArchivo>
<xsl:attribute name="etiquetaCFD">
<xsl:value-of select="$parsedXml/comprobante/inicioCFD/etiquetaCFD"/>
</xsl:attribute>
<xsl:value-of select="$parsedXml/comprobante/inicioCFD/idArchivo"/>
</idArchivo>
</comprobante>
</xsl:template>
<xsl:template name="unescape">
<xsl:param name="text"/>
<xsl:choose>
<xsl:when test="contains($text, '&')">
<xsl:value-of select="substring-before($text, '&')"/>
<xsl:variable name="afterAmp" select="substring-after($text, '&')"/>
<xsl:choose>
<xsl:when test="starts-with($afterAmp, 'amp;')">&</xsl:when>
<xsl:when test="starts-with($afterAmp, 'lt;')"><</xsl:when>
<xsl:when test="starts-with($afterAmp, 'gt;')">></xsl:when>
<xsl:when test="starts-with($afterAmp, 'quot;')">"</xsl:when>
<xsl:when test="starts-with($afterAmp, 'apos;')">'</xsl:when>
</xsl:choose>
<xsl:call-template name="unescape">
<xsl:with-param name="text" select="substring-after($afterAmp, ';')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="parseXml">
<xsl:param name="text"/>
<xsl:choose>
<xsl:when test="contains($text, '>')">
<xsl:variable name="topLevelTag">
<xsl:call-template name="getTopLevelTag">
<xsl:with-param name="text" select="$text"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="openingTag">
<xsl:value-of select="$topLevelTag"/>
</xsl:variable>
<xsl:variable name="tagName">
<xsl:call-template name="getTopLevelTagName">
<xsl:with-param name="text" select="$text"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="closingTag">
<xsl:value-of select="concat('</',$tagName,'>')"/>
</xsl:variable>
<xsl:variable name="firstNode">
<xsl:if test="not(contains($topLevelTag,'/>'))">
<xsl:value-of select="substring-before(substring-after($text,$openingTag),$closingTag)"/>
</xsl:if>
</xsl:variable>
<xsl:variable name="afterFirstNode">
<xsl:choose>
<xsl:when test="not(contains($topLevelTag,'/>'))">
<xsl:value-of select="substring-after($text,concat($firstNode,$closingTag))"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="substring-after($text,$topLevelTag)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:element name="{$tagName}">
<xsl:call-template name="createAttributes">
<xsl:with-param name="text" select="$topLevelTag"/>
</xsl:call-template>
<xsl:call-template name="parseXml">
<xsl:with-param name="text" select="$firstNode"/>
</xsl:call-template>
</xsl:element>
<xsl:call-template name="parseXml">
<xsl:with-param name="text" select="$afterFirstNode"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="getTopLevelTagName">
<xsl:param name="text"/>
<xsl:choose>
<xsl:when test="contains($text, '>')">
<xsl:variable name="tagWithAttributesWithoutEnd">
<xsl:value-of select="substring-before($text, '>')"/>
</xsl:variable>
<xsl:variable name="tagWithAttributesWithoutBegining">
<xsl:value-of select="substring-after($tagWithAttributesWithoutEnd, '<')"/>
</xsl:variable>
<xsl:variable name="tagName">
<xsl:choose>
<xsl:when test="contains($tagWithAttributesWithoutBegining,' ')">
<xsl:value-of
select="substring-before($tagWithAttributesWithoutBegining, ' ')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$tagWithAttributesWithoutBegining"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:value-of select="$tagName"/>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template name="getTopLevelTag">
<xsl:param name="text"/>
<xsl:choose>
<xsl:when test="contains($text, '>')">
<xsl:variable name="tagWithAttributesWithoutEnd">
<xsl:value-of select="substring-before($text, '>')"/>
</xsl:variable>
<xsl:value-of select="concat($tagWithAttributesWithoutEnd,'>')"/>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template name="createAttributes">
<xsl:param name="text"/>
<xsl:choose>
<xsl:when test="contains($text, '="')">
<xsl:variable name="attributeName">
<xsl:value-of select="substring-before(substring-after($text,' '),'="')"/>
</xsl:variable>
<xsl:message>
<xsl:value-of select="$text"/>
</xsl:message>
<xsl:variable name="attributeValue">
<xsl:value-of select="substring-before(substring-after($text,concat($attributeName,'="')),'"')"/>
</xsl:variable>
<xsl:attribute name="{$attributeName}">
<xsl:value-of select="$attributeValue"/>
</xsl:attribute>
<xsl:call-template name="createAttributes">
<xsl:with-param name="text" select="substring-after($text,concat($attributeName,'="',$attributeValue,'"'))"/>
</xsl:call-template>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
它產生我所需的輸出:
<comprobante xmlns:xsi="http://www.w3.org/2001/XMLSchema">
<idArchivo etiquetaCFD="NCR">182NAI053402</idArchivo>
</comprobante>
我發表我的作品,希望對任何其他人都有所幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.