XML / XSL / C# - 转化重复组分成若干文本行 [英] XML/XSL/C# - transforming repeating group into several text lines

查看:170
本文介绍了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:样式>


解决方案

您进行了一些错误:




  1. 您使用两个单独的for-each循环,而不是在一个循环中循环,所以你输出的第一行是从为了元素,接下来的两个是从项目元素。 (其实你不需要任何的循环。解决方案如下。)

  2. 您拼错 ShipMetod ,所以你的领域之一是误空白

  3. 您没有到位任何方法逃避任何 | 值可能存在的字段值。 (因为我不知道要做些什么什么我的解决方案并没有解决这个问题。)



一个更好的解决方案,是使用模板匹配字符串拼接



<预类=郎咸平的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>&#13;&#10;</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>&#13;&#10;</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:

  1. 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 the Item elements. (Actually you don't need any loops. Solution below.)
  2. You misspelled ShipMetod, so one of your fields is mistakenly blank.
  3. 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>&#13;&#10;</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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆