XSLT:如何将 XML 节点转换为字符串
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6696382/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
XSLT: How to convert XML Node to String
提问by Kalyan
<ROOT>
<A>
<B>TESTING</B>
</A>
</ROOT>
XSL:
XSL:
<xsl:variable name="nodestring" select="//A"/>
<xsl:value-of select="$nodestring"/>
I am trying to convert XML nodeset to string using XSL. Any thoughts?
我正在尝试使用 XSL 将 XML 节点集转换为字符串。有什么想法吗?
回答by jelovirt
You need to serialize the nodes. The most simple for your example would be something like
您需要序列化节点。你的例子最简单的就是这样
<xsl:template match="ROOT">
<xsl:variable name="nodestring">
<xsl:apply-templates select="//A" mode="serialize"/>
</xsl:variable>
<xsl:value-of select="$nodestring"/>
</xsl:template>
<xsl:template match="*" mode="serialize">
<xsl:text><</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>></xsl:text>
<xsl:apply-templates mode="serialize"/>
<xsl:text></</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>></xsl:text>
</xsl:template>
<xsl:template match="text()" mode="serialize">
<xsl:value-of select="."/>
</xsl:template>
The above serializer templates do not handle e.g. attributes, namespaces, or reserved characters in text nodes, but the concept should be clear. XSLT process works on a node tree and if you need to have access to "tags", you need to serialize the nodes.
上面的序列化器模板不处理例如属性、命名空间或文本节点中的保留字符,但概念应该很清楚。XSLT 过程适用于节点树,如果您需要访问“标签”,则需要序列化节点。
回答by Fran?ois Dispaux
Based on @jelovirt solution, here is a more complete piece of code:
基于@jelovirt 解决方案,这里有一段更完整的代码:
<xsl:template match="*" mode="serialize">
<xsl:text><</xsl:text>
<xsl:value-of select="name()"/>
<xsl:apply-templates select="@*" mode="serialize" />
<xsl:choose>
<xsl:when test="node()">
<xsl:text>></xsl:text>
<xsl:apply-templates mode="serialize" />
<xsl:text></</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>></xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text> /></xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="@*" mode="serialize">
<xsl:text> </xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>="</xsl:text>
<xsl:value-of select="."/>
<xsl:text>"</xsl:text>
</xsl:template>
<xsl:template match="text()" mode="serialize">
<xsl:value-of select="."/>
</xsl:template>
回答by Doug
In XSLT Version 3.0. See this W3 link for fn:serialize. This worked for me using SaxonPE.
在 XSLT 3.0 版中。有关fn:serialize 的信息,请参阅此 W3 链接。这对我使用 SaxonPE 有用。
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:output="http://www.w3.org/2010/xslt-xquery-serialization">
<xsl:variable name="output">
<output:serialization-parameters>
<output:method value="html"/>
</output:serialization-parameters>
</xsl:variable>
<xsl:template match="div">
<xsl:value-of select="serialize(., $output/output:serialization-parameters)" />
</xsl:template>
</xsl:stylesheet>
回答by Ilya Kharlamov
<xsl:template name="serializeNodeToString">
<xsl:param name="node"/>
<xsl:variable name="name" select="name($node)"/>
<xsl:if test="$name">
<xsl:value-of select="concat('<',$name)"/>
<xsl:for-each select="$node/@*">
<xsl:value-of select="concat(' ',name(),'="',.,'" ')"/>
</xsl:for-each>
<xsl:value-of select="concat('>',./text())"/>
</xsl:if>
<xsl:for-each select="$node/*">
<xsl:call-template name="serializeNodeToString">
<xsl:with-param name="node" select="."/>
</xsl:call-template>
</xsl:for-each>
<xsl:if test="$name">
<xsl:value-of select="concat('</',$name,'>')"/>
</xsl:if>
</xsl:template>
回答by Sergey Safarov
Saxon required for following solution. I find it here
以下解决方案需要撒克逊人。我在这里找到
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:saxon="http://saxon.sf.net/"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!-- To serialize with saxon:serialize() -->
<xsl:output name="default" indent="yes"
omit-xml-declaration="yes" />
<xsl:template match="*">
<xsl:variable name="node-set">
<xsl:element name="level1">
<xsl:element name="level2" />
<xsl:element name="level2" />
</xsl:element>
</xsl:variable>
<xsl:element name="input">
<xsl:copy-of select="$node-set" />
</xsl:element>
<xsl:element name="output">
<xsl:value-of select="saxon:serialize($node-set, 'default')" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
回答by Dmitriy.Sh.
My solution:
我的解决方案:
<xsl:template name="serializeNodeToString">
<xsl:param name="node" />
<xsl:variable name="name" select="name($node)" />
<xsl:text><</xsl:text>
<xsl:value-of select="$name" />
<xsl:for-each select="$node/@*">
<xsl:text> </xsl:text>
<xsl:value-of select="name()" /><xsl:text>="</xsl:text>
<xsl:value-of select="." />
<xsl:text>"</xsl:text>
<xsl:text> </xsl:text>
</xsl:for-each>
<xsl:text>></xsl:text>
<xsl:value-of select="./text()" />
<xsl:for-each select="$node/*">
<xsl:call-template name="serializeNodeToString">
<xsl:with-param name="node" select="."/>
</xsl:call-template>
</xsl:for-each>
<xsl:text></</xsl:text>
<xsl:value-of select="$name" />
<xsl:text>></xsl:text>
</xsl:template>
回答by mikey
<xsl:template match="A">
<xsl:variable name="nodes" select="." />
<xsl:copy-of select="$nodes"/>
</xsl:template>
Updated based on comments..
根据评论更新..
OK I've never done exactly what you need before, so take this with that grain of salt (I'm winging it). Basically you need to be very concerned about 2 things: characters that require escaping and white space. In this case, the string that empogave you in the comments above is more what you're after. Below is one way that you can make your XSL output that:
好吧,我以前从来没有完全做过你需要做的事情,所以把它和那粒盐一起拿走(我正在做它)。基本上你需要非常关注两件事:需要转义的字符和空格。在这种情况下,empo在上面的评论中给你的字符串更像是你所追求的。下面是一种可以使 XSL 输出满足以下条件的方法:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="A">
<input type="hidden" name="hiddenxml">
<xsl:attribute name="value">
<xsl:apply-templates select="." mode="id" />
</xsl:attribute>
</input>
</xsl:template>
<xsl:template match="*" mode="id" >
<xsl:text><</xsl:text><xsl:value-of select="name(.)" /><xsl:text>></xsl:text>
<xsl:apply-templates select="./*" mode="id" />
<xsl:value-of select="normalize-space(.)" />
<xsl:text></</xsl:text><xsl:value-of select="name(.)" /><xsl:text>></xsl:text>
</xsl:template>
</xsl:stylesheet>
You still need to be concerned with other characters that require escaping like " ' & I believe you can use translate or replace for those
您仍然需要关注其他需要转义的字符,例如 " ' & 我相信您可以对这些字符使用 translate 或 replace
回答by Dimitre Novatchev
Search for "XML pretty-printer". Or just have a look at the XSLT code of my XPath Visualizer(though it produces XML representation to be displayed in a browser, but you'll get the idea).
搜索“XML 漂亮打印机”。或者只是看看我的XPath Visualizer的 XSLT 代码(虽然它生成要在浏览器中显示的 XML 表示,但你会明白的)。
回答by david.perez
My solution is for Saxon HE, and have this advantages:
我的解决方案适用于 Saxon HE,并具有以下优势:
- it doesn't require licensing
- supports namespaces, CDATA, escaping of special characters and many advanced XML features.
- 它不需要许可
- 支持命名空间、CDATA、特殊字符转义和许多高级 XML 功能。
I've tried successfully with Saxon HE 9.5.X.
我已经成功地尝试了 Saxon HE 9.5.X。
It is about registering a custom extension functionwith these contents:
它是关于用这些内容注册一个自定义扩展函数:
import java.io.StringWriter;
import net.sf.saxon.expr.XPathContext;
import net.sf.saxon.lib.ExtensionFunctionCall;
import net.sf.saxon.lib.ExtensionFunctionDefinition;
import net.sf.saxon.om.Sequence;
import net.sf.saxon.om.StructuredQName;
import net.sf.saxon.s9api.Processor;
import net.sf.saxon.s9api.SaxonApiException;
import net.sf.saxon.s9api.Serializer;
import net.sf.saxon.s9api.XdmValue;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.value.SequenceType;
import net.sf.saxon.value.StringValue;
@SuppressWarnings("serial")
public class XmlSerializer extends ExtensionFunctionDefinition {
@Override
public StructuredQName getFunctionQName() {
return new StructuredQName("vis", "my.custom.uri", "serialize-xml");
}
@Override
public SequenceType[] getArgumentTypes() {
return new SequenceType[] { SequenceType.SINGLE_NODE };
}
@Override
public SequenceType getResultType(SequenceType[] sequenceTypes) {
return SequenceType.SINGLE_STRING;
}
@Override
public ExtensionFunctionCall makeCallExpression() {
return new ExtensionFunctionCall() {
@Override
public Sequence call(XPathContext ctx, Sequence[] secs) throws XPathException {
StringWriter escr = new StringWriter();
try {
if (secs.length == 0) {
throw new XPathException("Missing argument");
} else {
Serializer serializer = new Processor(ctx.getConfiguration()).newSerializer(escr);
serializador.setOutputProperty(Serializer.Property.OMIT_XML_DECLARATION, "yes");
serializer.serializeXdmValue(XdmValue.wrap(secs[0]));
}
return new StringValue(escr.toString());
} catch (SaxonApiException ex) {
throw new XPathException("Error when invoking serialize-xml()", ex);
}
}
};
}
}
You can use this function as follows:
您可以按如下方式使用此功能:
<xs:value-of xmlns:vis="my.custom.uri" select="vis:serialize-xml(someNode)"/>
The inverse process is documented here.
此处记录了相反的过程。
回答by Peter Krauss
About "convert Node to String"
关于“将节点转换为字符串”
With XSLT 1.0, you can use the XPath1.0 string()function of the Core Function Library, that converts a node to a string:
在 XSLT 1.0 中,您可以使用string()核心函数库的 XPath1.0函数,将节点转换为字符串:
<xsl:template match="A">
<xsl:variable name="nodeAsStr" select="string(.)" />
<xsl:copy-of select="$nodeAsStr"/><!-- or value-of -->
</xsl:template>
See "Function: string string(object)" at section 4.3.
请参阅第 4.3 节中的“函数:字符串 string(object)” 。
About "convert Node to XML pretty-printer"
关于“将节点转换为 XML 漂亮打印机”
It this another question, about "XML pretty-printer" or "XML dump" ... See good answers here.
这是另一个问题,关于“XML 漂亮打印机”或“XML 转储”......在这里看到好的答案。

