.net xdt transform only replaces first match - c#

I have a config file I'm transforming:
<?xml version="1.0" encoding="utf-8"?>
<TopNode>
<Sub>
<subnode>aaaa</subnode>
<othernode>sdfsfsdfsd</othernode>
</Sub>
<Sub>
<subnode>aaaa</subnode>
<othernode>iiiiiii</othernode>
</Sub>
<Sub>
<subnode>aaaa</subnode>
<othernode>blahblahblahblabhlahb</othernode>
</Sub>
<Sub>
<subnode>aaaa</subnode>
<othernode>sdfsdfseeferererer</othernode>
</Sub>
</TopNode>
I have this transform:
<?xml version="1.0" encoding="utf-8" ?>
<TopNode xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<Sub>
<subnode xdt:Transform="Replace">replaceallwiththis</subnode>
</Sub>
</TopNode>
It only replaces the first subnode match. How do I get it to replace all?
I also try like this but no work:
<subnode xdt:Locator="Condition(.)" xdt:Transform="Replace">replaceallwiththis</subnode>
I also trya dis but she a no work (only replaces first match):
<subnode xdt:Locator="XPath(//TopNode/Sub[subnode='aaaa']/subnode)" xdt:Transform="Replace">zzzzzzzzzzzzzzzzzzz</subnode>

Related

How to get nodes where his child node has some value

I have below xml structure:
<?xml version="1.0" encoding="UTF-8" ?>
<rss>
<channel>
<item>
<title>Some Title</title>
</wp:comment>
<wp:comment_approved><![CDATA[1]]></wp:comment_approved>
</wp:comment>
</wp:comment>
<wp:comment_approved><![CDATA[1]]></wp:comment_approved>
</wp:comment>
</item>
</channel>
</rss>
I can easily get all wp:comments by:
xmlNode.SelectNodes("*[name()='wp:comment']")
But how can I get all wp:comments where wp:comment_approved has value 1?
it's updated #Stefan Hegny answer, as you need not comment_approvedelement, but wp:comment
xmlNode.SelectNodes("//*[name()='wp:comment'][./*[local-name() = 'comment_approved' and . = '1']")
i'm not sure if default css locators working here, but in common css xPath i'll use this locator (logic is simple - you seach some element, that contains element with special parameter, so you can adjust this locator to your needs):
//someTag[./innerTag[text() = '1']]

How to call c# function in xsl

im trying to call a c# function in xsl. I have to map some values into a xml. There are 3 principal components
-xsl
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:var="http://schemas.microsoft.com/BizTalk/2003/var"
xmlns:ns0="http://iti/serv/dataloader"
xmlns:HelpersNS0="http://ri/clus/mapperhelpers/v1.0/I/F/C/CustomComponents ">
<xsl:output omit-xml-declaration="yes" method="xml" version="1.0" />
<xsl:template match="/*[local-name()='InvokeDataLoader']">
<ns0:scriptToExecute>
<xsl:value-of select="HelpersNS0:GetDataLoaderPath()"/>
</ns0:scriptToExecute>
</xsl:template>
</xsl:stylesheet>
-xml where i get c# assembly
<?xml version="1.0" encoding="UTF-8" ?>
<ExtensionObjects>
<ExtensionObject
Namespace="http://ri/clus/mapperhelpers/v1.0/I/F/C/CustomComponents"
AssemblyName="G.T.I_Fatt.CustomComponents, Version=1.0.0.0,Culture=neutral, PublicKeyToken=6ecedb456a4a8c16"
ClassName="G.T.I_Fatt.CustomComponents.MapperHelpers" />
</ExtensionObjects>
-xml to transform
<?xml version="1.0" encoding="UTF-8" ?>
<InvokeDataLoader xmlns="http://iti/serv/dataloader">
<scriptToExecute/>
<inputFile/>
</InvokeDataLoader>
But when i try to transform i get this error: "namespace does not contain any functions"
I notice you have xmlns:HelpersNS0="http://ri/clus/mapperhelpers/v1.0/I/F/C/CustomComponents ts"> in the XSLT yet Namespace="http://ri/clus/mapperhelpers/v1.0/I/F/C/CustomComponents" (without the ts) in the other file. So the namespace does not match.

How to Split an XML file into multiple XML Files

I am trying to split a XML file to multiple small xml files in C#.net and am
trying to get the best possible approach to this. Any help on this will be
great... Sample example on what I am trying to do...
Source XML document
<?xml version="1.0" standalone="yes"?>
<DATABASE>
<DOC>
<DOCID>8510188</DOCID>
<ISSUE>2010</ISSUE>
<CAT>Literature and Art</CAT>
<TITLE>Test</TITLE>
<TEXT>Test</TEXT>
</DOC>
<DOC>
<DOCID>1510179</DOCID>
<ISSUE>2012</ISSUE>
<CAT>Miscellaneous</CAT>
<TITLE>Test</TITLE>
<TEXT>Test</TEXT>
</DOC>
</DATABASE>
Should split to two xml documents as below
1)
<?xml version="1.0" standalone="yes"?>
<DATABASE>
<DOC>
<DOCID>8510188</DOCID>
<ISSUE>2010</ISSUE>
<CAT>Literature and Art</CAT>
<TITLE>Test</TITLE>
<TEXT>Test</TEXT>
</DOC>
</DATABASE>
2)
<?xml version="1.0" standalone="yes"?>
<DATABASE>
<DOC>
<DOCID>1510179</DOCID>
<ISSUE>2012</ISSUE>
<CAT>Miscellaneous</CAT>
<TITLE>Test</TITLE>
<TEXT>Test</TEXT>
</DOC>
</DATABASE>
Well, I'd use LINQ to XML:
XDocument doc = XDocument.Load("test.xml");
var newDocs = doc.Descendants("DOC")
.Select(d => new XDocument(new XElement("DATABASE", d)));
foreach (var newDoc in newDocs)
{
newDoc.Save(/* work out filename here */);
}
(I'm assuming you want to save them. Maybe you don't need to. I've tested this just by printing them out to the console instead.)

C# XPath Soap, how to navigate to embedded node

In C#, Asp.Net, I am trying to return the Error node inside of BISearchResponse:
I am able to get the GetWireResult node returned in an XMLNode.
How do I get to the Error node?
<?xml version="1.0" encoding="utf-8" ?>
- <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
- <soap:Body>
- <GetWireResponse xmlns="http://OpenSolutions.com/">
<GetWireResult><?xml version="1.0"?>
<BISearchResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Error xmlns="https://bixg.choicepoint.com/webservices/3.0">
<Message>BI System: Failed to Login</Message>
<Code>536870917</Code>
</Error>
</BISearchResponse>
</GetWireResult>
</GetWireResponse>
</soap:Body>
</soap:Envelope>
My code:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(result);
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlDoc.NameTable);
nsmgr.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");
nsmgr.AddNamespace("ab", "http://OpenSolutions.com/");
nsmgr.AddNamespace("bg", " https://bixg.choicepoint.com/webservices/3.0");
nsmgr.AddNamespace("xsd", "http://www.w3.org/2001/XMLSchema");
nsmgr.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
XmlNode xmlnode = xmlDoc.DocumentElement.SelectSingleNode("/soap:Envelope/soap:Body/ab:GetWireResponse", nsmgr);
This works to here.
.
I am adding the xml here, but it is only visible in edit mode.
<?xml version="1.0" encoding="utf-8" ?>
- <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
- <soap:Body>
- <GetWireResponse xmlns="http://OpenSolutions.com/">
<GetWireResult><?xml version="1.0"?> <BISearchResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <Error xmlns="https://bixg.choicepoint.com/webservices/3.0"> <Message>BI System: Failed to Login</Message> <Code>536870917</Code> </Error> </BISearchResponse></GetWireResult>
</GetWireResponse>
</soap:Body>
</soap:Envelope>
In debug mode, when you copy this XML, try choose another debug visualizer, e.g. "Text visualizer". You can select it clicking the magnifying glass icon in datatip.
I think your XML looks like:
<?xml version="1.0" encoding="utf-8" ?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetWireResponse xmlns="http://OpenSolutions.com/">
<GetWireResult>
<?xml version="1.0"?>
<BISearchResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Error xmlns="https://bixg.choicepoint.com/webservices/3.0">
<Message>BI System: Failed to Login</Message>
<Code>536870917</Code>
</Error>
</BISearchResponse>
</GetWireResult>
</GetWireResponse>
</soap:Body>
</soap:Envelope>
or
<?xml version="1.0" encoding="utf-8" ?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetWireResponse xmlns="http://OpenSolutions.com/">
<GetWireResult>
<![CDATA[
<?xml version="1.0"?>
<BISearchResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Error xmlns="https://bixg.choicepoint.com/webservices/3.0">
<Message>BI System: Failed to Login</Message>
<Code>536870917</Code>
</Error>
</BISearchResponse>
]]>
</GetWireResult>
</GetWireResponse>
</soap:Body>
</soap:Envelope>
No matter. So you can select GetWireResult using following XPath:
/soap:Envelope/soap:Body/ab:GetWireResponse/ab:GetWireResult
and then load it content in new XML document and get desired response.
You're almost there. Extend your XPath
"/soap:Envelope/soap:Body/ab:GetWireResponse"
to
"/soap:Envelope/soap:Body/ab:GetWireResponse/ab:GetWireResult/ab:BISearchResponse/bg:Error"
However that extra XML prologue stuck in there in the middle, <?xml version="1.0"?>, makes the XML not well-formed. I'm surprised it can be processed at all. I would think the C# API should throw an exception on xmlDoc.LoadXml(result).
Another approach, seeing as the above does not return anything for you, would be to use your C# code to explore the structure of the XML document and print out the children of each node. E.g. if you are getting a node for "/soap:Envelope/soap:Body/ab:GetWireResponse" but not for "/soap:Envelope/soap:Body/ab:GetWireResponse/ab:GetWireResult", does ab:GetWireResponse have what text node children, and if so, what are their values (contents)? That should give insight into why the XPath is not working.
If there's a block of unparsed (i.e. escaped) XML in there, you could either copy it out and parse it as XML like you said, or just search for the pattern you need using a regexp... depending on the complexity.

Reading different XML with C#/DOM

I am currently using DOM to navigate xml in my C# project. However, some XML that i've come across lately is a bit different.
whereas usually I have:
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<entry>
<author>
<name>Me =)</name>
</author>
<content>
<somefield1>
<Subfield>subfield data</subfield>
</somefield>
</content>
</entry>
</feed>
and can navigate using foreach entry as entry, selectsinglenode(/content/somefield1/subfield), innertext to get the data from the subfield for each entry, the new XML looks like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<atom:feed xmlns:atom="http://www.w3.org/2005/Atom">
<atom:entry>
<atom:author>
<name>Me =)</name>
</atom:author>
<atom:content>
<somefield1>
<Subfield>subfield data</subfield>
</somefield>
</atom:content>
</atom:entry>
</atom:feed>
selectsinglenode(/atom:content/somefield1/subfield) is definitely not going to work...any suggestions?
atom: is just the namespace, and possibly you might just ignore it. If it still not works, you may have to use:
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("atom", "http://www.w3.org/2005/Atom");
selectsinglenode("atom:content/somefield1/subfield", nsmgr);
Which is documented here

Categories

Resources