如何从 XElements 列表中删除不需要的节点?
How can I remove an unwanted node from a list of XElements?
我需要使用 C# 来修改服务的响应,然后再将其传递给调用者。该服务接受一系列 XML 格式的请求,格式化消息并将其发送到服务。响应看起来类似于:
<SvcRes>
<SvcVer>1.0</SvcVer>
<MsgUUID>12345678-1234-1234-1234-123456789012</MsgUUID>
<Svc>
<SvcParms>
<ApplID>App</ApplID>
<SvcID>AppSrch</SvcID>
<SvcVer>1.0</SvcVer>
</SvcParms>
<MsgData>
<AppResData>
<Key>xxxxxxxx</Key>
<Rslt>xxxxxxxx</Rslt>
<ErrCde>0</ErrCde>
<ApplMsgLst>
<ApplMsg>
<ApplMsgApplId>D6</ApplMsgApplId>
<ApplMsgNbr>0</ApplMsgNbr>
<ApplMsgTxt>INQUIRY COMPLETE 09:23:53</ApplMsgTxt>
<ApplMsgErrInd>N</ApplMsgErrInd>
</ApplMsg>
</ApplMsgLst>
</AppResData>
</MsgData>
<ErrCde>0</ErrCde>
<ErrMsg/>
</Svc>
<Svc>
<SvcParms>
<ApplID>DP</ApplID>
<SvcID>DPKywrd</SvcID>
<SvcVer>1.0</SvcVer>
<RqstUUID>12345678-1234-1234-1234-123456789012</RqstUUID>
</SvcParms>
<MsgData>
<AppResData>
<Key>xxxxxxxx</Key>
<Rslt>xxxxxxxx</Rslt>
<ErrCde>0</ErrCde>
<ApplMsgLst>
<ApplMsg>
<ApplMsgApplId>D6</ApplMsgApplId>
<ApplMsgNbr>0</ApplMsgNbr>
<ApplMsgTxt>INQUIRY COMPLETE 09:23:53</ApplMsgTxt>
<ApplMsgErrInd>N</ApplMsgErrInd>
</ApplMsg>
</ApplMsgLst>
</AppResData>
</MsgData>
<ErrCde>0</ErrCde>
<ErrMsg/>
<Svc>
<ErrCde>0</ErrCde>
<ErrMsg>Success</ErrMsg>
</SvcRes>
我需要取出 AppResData 节点,然后从每个节点中取出 ApplMsgLst 节点,然后再将结果发送回调用方。结果 XML 应该是这样的:
<AppResData>
<Key>xxxxxxxx</Key>
<Rslt>xxxxxxxx</Rslt>
<ErrCde>0</ErrCde>
</AppResData>
<AppResData>
<Key>xxxxxxxx</Key>
<Rslt>xxxxxxxx</Rslt>
<ErrCde>0</ErrCde>
</AppResData>
我可以使用以下两行代码获取 XElement 节点列表:
var xml = XElement.Parse(xmlResponse);
var msgData = xml.DescendantsAndSelf("MsgData");
- 然后我可以做 string.Concat(msgData.Nodes()) 将最终字符串 return 发送给调用者——但此时我不知道如何删除内部 ApplMsgLst 节点。我试过将它转换回字符串并重新解析,但它当然会抱怨多个根元素。我已经尝试了所有我能想到的删除组合,但他们总是删除太多(所有内容)或什么都不删除..
还有其他方法吗?没有文件,这是 SOAP 网络服务中的所有字符串数据。
这是一个基于 XSLT 的解决方案。
参数:
- 输入 XML 作为字符串数据类型。
- 作为文件的 XSLT。
- 输出 XML 作为字符串数据类型。
XSLT
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="/SvcRes">
<root>
<xsl:for-each select="Svc/MsgData/AppResData">
<xsl:copy>
<xsl:copy-of select="Key"/>
<xsl:copy-of select="Rslt"/>
<xsl:copy-of select="ErrCde"/>
</xsl:copy>
</xsl:for-each>
</root>
</xsl:template>
</xsl:stylesheet>
c#
void Main()
{
const string XSLTFILE = @"e:\Temp\DaveN59.xslt";
string inputXML = @"<SvcRes>
...
</SvcRes>";
try
{
StringReader rdr = new StringReader(inputXML);
XPathDocument XPathDoc = new XPathDocument(rdr);
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(XSLTFILE);
StringWriter sw = new StringWriter();
using (XmlWriter xwo = XmlWriter.Create(sw, xslt.OutputSettings))
{
xslt.Transform(XPathDoc, xwo);
}
Console.WriteLine(sw.ToString());
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
输出XML
<root>
<AppResData>
<Key>xxxxxxxx</Key>
<Rslt>xxxxxxxx</Rslt>
<ErrCde>0</ErrCde>
</AppResData>
<AppResData>
<Key>xxxxxxxx</Key>
<Rslt>xxxxxxxx</Rslt>
<ErrCde>0</ErrCde>
</AppResData>
</root>
您可以尝试使用 Cinchoo ETL - 一个可以轻松完成此转换的开源库
StringBuilder xml = new StringBuilder();
using (var r = ChoXmlReader.LoadText("*** YOUR XML CONTENTS ***")
.WithXPath("//AppResData")
.WithField("Key")
.WithField("Rslt")
.WithField("ErrCde")
)
{
using (var w = new ChoXmlWriter(xml)
)
{
w.Write(r);
}
}
Console.WriteLine(xml.ToString());
输出:
<Root>
<AppResData>
<Key>xxxxxxxx</Key>
<Rslt>xxxxxxxx</Rslt>
<ErrCde>0</ErrCde>
</AppResData>
<AppResData>
<Key>xxxxxxxx</Key>
<Rslt>xxxxxxxx</Rslt>
<ErrCde>0</ErrCde>
</AppResData>
</Root>
我需要使用 C# 来修改服务的响应,然后再将其传递给调用者。该服务接受一系列 XML 格式的请求,格式化消息并将其发送到服务。响应看起来类似于:
<SvcRes>
<SvcVer>1.0</SvcVer>
<MsgUUID>12345678-1234-1234-1234-123456789012</MsgUUID>
<Svc>
<SvcParms>
<ApplID>App</ApplID>
<SvcID>AppSrch</SvcID>
<SvcVer>1.0</SvcVer>
</SvcParms>
<MsgData>
<AppResData>
<Key>xxxxxxxx</Key>
<Rslt>xxxxxxxx</Rslt>
<ErrCde>0</ErrCde>
<ApplMsgLst>
<ApplMsg>
<ApplMsgApplId>D6</ApplMsgApplId>
<ApplMsgNbr>0</ApplMsgNbr>
<ApplMsgTxt>INQUIRY COMPLETE 09:23:53</ApplMsgTxt>
<ApplMsgErrInd>N</ApplMsgErrInd>
</ApplMsg>
</ApplMsgLst>
</AppResData>
</MsgData>
<ErrCde>0</ErrCde>
<ErrMsg/>
</Svc>
<Svc>
<SvcParms>
<ApplID>DP</ApplID>
<SvcID>DPKywrd</SvcID>
<SvcVer>1.0</SvcVer>
<RqstUUID>12345678-1234-1234-1234-123456789012</RqstUUID>
</SvcParms>
<MsgData>
<AppResData>
<Key>xxxxxxxx</Key>
<Rslt>xxxxxxxx</Rslt>
<ErrCde>0</ErrCde>
<ApplMsgLst>
<ApplMsg>
<ApplMsgApplId>D6</ApplMsgApplId>
<ApplMsgNbr>0</ApplMsgNbr>
<ApplMsgTxt>INQUIRY COMPLETE 09:23:53</ApplMsgTxt>
<ApplMsgErrInd>N</ApplMsgErrInd>
</ApplMsg>
</ApplMsgLst>
</AppResData>
</MsgData>
<ErrCde>0</ErrCde>
<ErrMsg/>
<Svc>
<ErrCde>0</ErrCde>
<ErrMsg>Success</ErrMsg>
</SvcRes>
我需要取出 AppResData 节点,然后从每个节点中取出 ApplMsgLst 节点,然后再将结果发送回调用方。结果 XML 应该是这样的:
<AppResData>
<Key>xxxxxxxx</Key>
<Rslt>xxxxxxxx</Rslt>
<ErrCde>0</ErrCde>
</AppResData>
<AppResData>
<Key>xxxxxxxx</Key>
<Rslt>xxxxxxxx</Rslt>
<ErrCde>0</ErrCde>
</AppResData>
我可以使用以下两行代码获取 XElement 节点列表:
var xml = XElement.Parse(xmlResponse);
var msgData = xml.DescendantsAndSelf("MsgData");
- 然后我可以做 string.Concat(msgData.Nodes()) 将最终字符串 return 发送给调用者——但此时我不知道如何删除内部 ApplMsgLst 节点。我试过将它转换回字符串并重新解析,但它当然会抱怨多个根元素。我已经尝试了所有我能想到的删除组合,但他们总是删除太多(所有内容)或什么都不删除..
还有其他方法吗?没有文件,这是 SOAP 网络服务中的所有字符串数据。
这是一个基于 XSLT 的解决方案。
参数:
- 输入 XML 作为字符串数据类型。
- 作为文件的 XSLT。
- 输出 XML 作为字符串数据类型。
XSLT
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" omit-xml-declaration="yes"/>
<xsl:template match="/SvcRes">
<root>
<xsl:for-each select="Svc/MsgData/AppResData">
<xsl:copy>
<xsl:copy-of select="Key"/>
<xsl:copy-of select="Rslt"/>
<xsl:copy-of select="ErrCde"/>
</xsl:copy>
</xsl:for-each>
</root>
</xsl:template>
</xsl:stylesheet>
c#
void Main()
{
const string XSLTFILE = @"e:\Temp\DaveN59.xslt";
string inputXML = @"<SvcRes>
...
</SvcRes>";
try
{
StringReader rdr = new StringReader(inputXML);
XPathDocument XPathDoc = new XPathDocument(rdr);
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(XSLTFILE);
StringWriter sw = new StringWriter();
using (XmlWriter xwo = XmlWriter.Create(sw, xslt.OutputSettings))
{
xslt.Transform(XPathDoc, xwo);
}
Console.WriteLine(sw.ToString());
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
输出XML
<root>
<AppResData>
<Key>xxxxxxxx</Key>
<Rslt>xxxxxxxx</Rslt>
<ErrCde>0</ErrCde>
</AppResData>
<AppResData>
<Key>xxxxxxxx</Key>
<Rslt>xxxxxxxx</Rslt>
<ErrCde>0</ErrCde>
</AppResData>
</root>
您可以尝试使用 Cinchoo ETL - 一个可以轻松完成此转换的开源库
StringBuilder xml = new StringBuilder();
using (var r = ChoXmlReader.LoadText("*** YOUR XML CONTENTS ***")
.WithXPath("//AppResData")
.WithField("Key")
.WithField("Rslt")
.WithField("ErrCde")
)
{
using (var w = new ChoXmlWriter(xml)
)
{
w.Write(r);
}
}
Console.WriteLine(xml.ToString());
输出:
<Root>
<AppResData>
<Key>xxxxxxxx</Key>
<Rslt>xxxxxxxx</Rslt>
<ErrCde>0</ErrCde>
</AppResData>
<AppResData>
<Key>xxxxxxxx</Key>
<Rslt>xxxxxxxx</Rslt>
<ErrCde>0</ErrCde>
</AppResData>
</Root>