XML / XSL / C# - 转化重复组分成若干文本行 [英] XML/XSL/C# - transforming repeating group into several text lines
本文介绍了XML / XSL / C# - 转化重复组分成若干文本行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我想从样本XML转换重复组分成两个分隔的文本行。这里是我当前的代码版本:
字符串orderXml =
@其中p XML版本='1.0'编码='UTF-8'>
<订单ID ='79223510'>
<状态>新< /状态>
< ShipMethod>标准国际< / ShipMethod>
< ToCity>东京< / ToCity>
<项目>
<项目>
< SKU> SKU-1234567890< / SKU>
<数量> 1< /数量>
<价格> 99.95< /价格>
< /项目>
<项目>
< SKU> SKU-1234567899< / SKU>
<数量> 1< /数量>
<价格> 199.95< /价格>
< /项目>
< /项目>
< /排序>,
StringReader海峡=新StringReader(orderXml);
变种XSLT =新的XmlTextReader的(新StringReader(
@< XML版本='1.0'编码='UTF-8'>+
< ;的xsl:样式版本='1.0'的xmlns:XSL =HTTP://www.w3.org/1999/XSL/Transform'>+
< XSL:输出方法= 文本缩进='没有'/>中+
< - 换行字符变量 - >中+
< XSL:变量名='换行>中+
< XSL:文本>&安培;#13;&安培;#10;< / XSL:文本>中+
< / XSL:变量>+
< XSL:变量名='空'>中+
< XSL:文本>< / XSL:文本>中+
< / XSL:变量> ;+
<的xsl:模板匹配='/'>中+
<的xsl:for-每个选择=订单>中+
<的xsl:value-of的选择=@ ID/> |+
< XSL:选择=状态/>值的; |+
<的xsl:value-of的选择='ShipMetod/> |+
< XSL:选择='ToCity/>值的; |+
< ;的xsl:value-of的选择='$换行/>中+
< /的xsl:for-每个>+
<的xsl:for-每个选择='订单/项目/项目'>中+
< XSL:选择=SKU/>值的; |+
<的xsl:value-of的选择='数量/> |+
< XSL:选择=价值,价格/> |+
<的xsl:value-of的选择='$换行/ >中+
< /的xsl:for-每个>+
< / XSL:模板>+
< / XSL:样式>
));
XDOC VAR =新的XPathDocument(STR);
变种XTR =新System.Xml.Xsl.XslCompiledTransform();
xTr.Load(XSLT);
StringBuilder的SB =新的StringBuilder();
StringWriter的作家=新的StringWriter(某人);
xTr.Transform(XDOC,空,作家);
的String [] =行sb.ToString()斯普利特(新的String [] {\\\
},StringSplitOptions.RemoveEmptyEntries)。
lines.ToList()的ForEach(System.Console.Write)。
这代码当前产生以下输出:
79223510 |新||东京|
SKU-1234567890 | 1 | 99.95 |
SKU-1234567899 | 1 | 199.95 |
和我想它产生以下之一:
79223510 |新||东京| SKU-1234567890 | 1 | 99.95 |
79223510 |新||东京| SKU-1234567899 | 1 | 199.95 |
只要使用XSL转换。请指教。
感谢您。
P.S。以文本形式添加XSL以方便您阅读:
@< XML版本='1.0'编码='UTF-8 ?'>
<的xsl:样式版本='1.0'的xmlns:XSL =HTTP://www.w3.org/1999/XSL/Transform'>
< XSL:输出方法=文本缩进='没有'/>
<! - 换行字符变量 - >
< XSL:变量名='新行'>
< XSL:文本>&安培;#13;&安培;#10;< / XSL:文本>
< / XSL:变量>
< XSL:变量名='空'>
< XSL:文本>< / XSL:文本>
< / XSL:变量>
<的xsl:模板匹配='/'>
<的xsl:for-每个选择='订购'>
<的xsl:值选='@ ID/> |
<的xsl:值选='状态'/> |
<的xsl:值选='ShipMetod/> |
<的xsl:值选='ToCity/> |
<的xsl:值选='$换行/>
< /的xsl:for-每个>
<的xsl:for-每个选择='订单/项目/项目'>
<的xsl:value-of的选择=SKU/> |
<的xsl:值选='数量'/> |
<的xsl:值选='价格'/> |
<的xsl:值选='$换行/>
< /的xsl:for-每个>
< / XSL:模板>
< / XSL:样式>
解决方案
您进行了一些错误:
- 您使用两个单独的for-each循环,而不是在一个循环中循环,所以你输出的第一行是从
为了
元素,接下来的两个是从项目
元素。 (其实你不需要任何的循环。解决方案如下。) - 您拼错
ShipMetod
,所以你的领域之一是误空白 - 您没有到位任何方法逃避任何
|
值可能存在的字段值。 (因为我不知道要做些什么什么我的解决方案并没有解决这个问题。)
一个更好的解决方案,是使用模板匹配字符串拼接
<预类=郎咸平的XML prettyprint-覆盖>
<的xsl:样式版本=1.0 的xmlns:XSL =HTTP://www.w3.org/1999/XSL/Transform'>
< XSL:输出方法=文本缩进=无媒体类型=text / plain的/>
< XSL:变量名='新行'>< XSL:文本>&安培;#13;&安培;#10;< / XSL:文本>< / XSL:变量>
< XSL:变量名='分隔符'> |< / XSL:变量>
<! - 在默认情况下,不会复制任何节点输出 - >
<的xsl:模板匹配=节点()| @ *>< XSL:申请模板选择=节点()| @ */>< / XSL:模板>
<的xsl:模板匹配=/订单/项目/项目><的xsl:value-of的
选择=CONCAT(
../ .. / @ ID,$分界,
../../Status,$分界,
../../ShipMethod,$分界,
../../ToCity,$分隔符,
SKU,$分界,
数量,$分界,
价格,$分界,
$行)/>< / XSL:模板>
< / XSL:样式>
这将产生以下的输出:
79223510 |新|标准国际|东京| SKU-1234567890 | 1 | 99.95 |
79223510 |新|标准国际|东京| SKU-1234567890 | 1 | 199.95 |
I wanted to transform repeating group from the sample XML into two delimited text lines. Here is my current code version:
string orderXml =
@"<?xml version='1.0' encoding='utf-8'?>
<Order id='79223510'>
<Status>new</Status>
<ShipMethod>Standard International</ShipMethod>
<ToCity>Tokyo</ToCity>
<Items>
<Item>
<SKU>SKU-1234567890</SKU>
<Quantity>1</Quantity>
<Price>99.95</Price>
</Item>
<Item>
<SKU>SKU-1234567899</SKU>
<Quantity>1</Quantity>
<Price>199.95</Price>
</Item>
</Items>
</Order>";
StringReader str = new StringReader(orderXml);
var xslt = new XmlTextReader(new StringReader(
@"<?xml version='1.0' encoding='UTF-8'?>" +
"<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>" +
"<xsl:output method='text' indent='no'/>" +
"<!-- New line character variable -->" +
"<xsl:variable name='newline'>" +
"<xsl:text> </xsl:text>" +
"</xsl:variable>" +
"<xsl:variable name='empty'>" +
"<xsl:text></xsl:text>" +
"</xsl:variable>" +
"<xsl:template match='/'>" +
"<xsl:for-each select='Order'>" +
"<xsl:value-of select='@id'/>|" +
"<xsl:value-of select='Status'/>|" +
"<xsl:value-of select='ShipMetod'/>|" +
"<xsl:value-of select='ToCity'/>|" +
"<xsl:value-of select='$newline'/>" +
"</xsl:for-each>" +
"<xsl:for-each select='Order/Items/Item'>" +
"<xsl:value-of select='SKU'/>|" +
"<xsl:value-of select='Quantity'/>|" +
"<xsl:value-of select='Price'/>|" +
"<xsl:value-of select='$newline'/>" +
"</xsl:for-each>" +
"</xsl:template>" +
"</xsl:stylesheet>"
));
var xDoc = new XPathDocument(str);
var xTr = new System.Xml.Xsl.XslCompiledTransform();
xTr.Load(xslt);
StringBuilder sb = new StringBuilder();
StringWriter writer = new StringWriter(sb);
xTr.Transform(xDoc, null, writer);
string[] lines = sb.ToString().Split(new string[] {"\n"}, StringSplitOptions.RemoveEmptyEntries);
lines.ToList().ForEach(System.Console.Write);
This code currently produces the following output:
79223510|new||Tokyo|
SKU-1234567890|1|99.95|
SKU-1234567899|1|199.95|
and I wanted it to produce the following one:
79223510|new||Tokyo|SKU-1234567890|1|99.95|
79223510|new||Tokyo|SKU-1234567899|1|199.95|
by just using XSL transformation. Please advise.
Thank you.
P.S. Added XSL in a text form for easier reading:
@<?xml version='1.0' encoding='UTF-8'?>
<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
<xsl:output method='text' indent='no'/>
<!-- New line character variable -->
<xsl:variable name='newline'>
<xsl:text> </xsl:text>
</xsl:variable>
<xsl:variable name='empty'>
<xsl:text></xsl:text>
</xsl:variable>
<xsl:template match='/'>
<xsl:for-each select='Order'>
<xsl:value-of select='@id'/>|
<xsl:value-of select='Status'/>|
<xsl:value-of select='ShipMetod'/>|
<xsl:value-of select='ToCity'/>|
<xsl:value-of select='$newline'/>
</xsl:for-each>
<xsl:for-each select='Order/Items/Item'>
<xsl:value-of select='SKU'/>|
<xsl:value-of select='Quantity'/>|
<xsl:value-of select='Price'/>|
<xsl:value-of select='$newline'/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
解决方案
You are making a few mistakes:
- You are using two separate for-each loops rather than a loop in a loop, so your first line of output is from the
Order
element, and the next two are from theItem
elements. (Actually you don't need any loops. Solution below.) - You misspelled
ShipMetod
, so one of your fields is mistakenly blank. - You don't have any method in place to escape any
|
values that may be present in the field values. (My solution doesn't solve this problem since I'm not sure what you want to do about it.)
A better solution is to use template matching and string-concatenation.
<xsl:stylesheet version="1.0" xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
<xsl:output method="text" indent="no" media-type="text/plain" />
<xsl:variable name='newline'><xsl:text> </xsl:text></xsl:variable>
<xsl:variable name='delimiter'>|</xsl:variable>
<!-- by default, don't copy any nodes to output -->
<xsl:template match="node()|@*"><xsl:apply-templates select="node()|@*"/></xsl:template>
<xsl:template match="/Order/Items/Item"><xsl:value-of
select="concat(
../../@id, $delimiter,
../../Status, $delimiter,
../../ShipMethod, $delimiter,
../../ToCity, $delimiter,
SKU, $delimiter,
Quantity, $delimiter,
Price, $delimiter,
$newline)"/></xsl:template>
</xsl:stylesheet>
This produces the following output:
79223510|new|Standard International|Tokyo|SKU-1234567890|1|99.95|
79223510|new|Standard International|Tokyo|SKU-1234567890|1|199.95|
这篇关于XML / XSL / C# - 转化重复组分成若干文本行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文