Getting the failed-assert from the sch file - schema

I have an .sch file provided by PEPPOL website: http://docs.peppol.eu/poacc/billing/3.0/files/PEPPOL-EN16931-UBL.sch and we need to convert it to .xsl. We have done the conversion using a tool called oXygen.
This is the snipped from .sch that generates the [BR-S-06]
<rule context="cac:AllowanceCharge[cbc:ChargeIndicator=false()]/cac:TaxCategory[normalize-space(cbc:ID)='S'][cac:TaxScheme/normalize-space(upper-case(cbc:ID))='VAT']">
<assert id="BR-S-06" flag="fatal" test="(cbc:Percent) > 0">[BR-S-06]-In a Document level allowance (BG-20) where the Document level allowance VAT category code (BT-95) is "Standard rated" the Document level allowance VAT rate (BT-96) shall be greater than zero.</assert>
</rule>
This is how I am expecting a rule to show as:
<!--ASSERT -->
<xsl:choose>
<xsl:when test="#listID = 'UNCL1001'"/>
<xsl:otherwise>
<svrl:failed-assert xmlns:svrl="http://purl.oclc.org/dsdl/svrl" test="#listID = 'BR-S-06'">
<xsl:attribute name="id">BR-S-06</xsl:attribute>
<xsl:attribute name="flag">fatal</xsl:attribute>
<xsl:attribute name="location">
<xsl:apply-templates select="." mode="schematron-select-full-path"/>
</xsl:attribute>
<svrl:text>[BR-S-06]-In a Document level allowance (BG-20) where the Document level allowance VAT category code (BT-95) is "Standard rated" the Document level allowance VAT rate (BT-96) shall be greater than zero.</svrl:text>
</svrl:failed-assert>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates select="#*|*" mode="M7"/>
This is how it is actually shown:
<!--ASSERT -->
<xsl:choose>
<xsl:when test="(cbc:Percent) > 0"/>
<xsl:otherwise>
<xsl:message xmlns:iso="http://purl.oclc.org/dsdl/schematron">
<xsl:text>[BR-S-06]-In a Document level allowance (BG-20) where the Document level allowance VAT category code (BT-95) is "Standard rated" the Document level allowance VAT rate (BT-96) shall be greater than zero.</xsl:text>
</xsl:message>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates select="#*|node()" mode="M10"/>
I am expecting to see the failed-assert element because it also contains the id/flag/location rather then what i currently get which is a message.
To run the validation using Saxon we have the following code:
public static Dictionary<string, List<ValidationResult>> ValidateXML(string xslTemplate, string xslName, XmlDocument document)
{
Dictionary<string, List<ValidationResult>> resultToReturn = new Dictionary<string, List<ValidationResult>>();
XmlNamespaceManager xmlNamespacesForDocument = GetAllNamespaces(document);
var transformAssertFailed = new List<ValidationResult>();
var processor = new Processor();
var compiler = processor.NewXsltCompiler();
var executable = compiler.Compile(new MemoryStream(Encoding.UTF8.GetBytes(xslTemplate)));
var destination = new DomDestination();
MemoryStream xmlStream = new MemoryStream();
document.Save(xmlStream);
xmlStream.Position = 0;
using (xmlStream)
{
var transformer = executable.Load();
transformer.SetInputStream(xmlStream, new Uri("file:///C:/"));
transformer.Run(destination);
}
return resultToReturn;
}
I am not sure what is wrong here, maybe the .sch file that I started with or maybe the .sch to .xsl converter.

I have posted the same question on the oXygen form here and I got my question answered.

Related

Creating Random string containing over 25 characters of numbers and letters (upper and lower case)

How to create a Random string longer than 25 characters consisting of of digits and letters with XSLT?
Example: Khb34KXQ23ib34KDNBBE342nQE
My XSLT is like this:
<xsl:function name="kh:shortRandom">
<xsl:sequence select="generate-id()"/>
</xsl:function>
<xsl:template match="/">
<test>
<randomId><xsl:value-of select="concat(kh:shortRandom(), kh:shortRandom(), kh:shortRandom(), kh:shortRandom())"/></randomId>
</test>
</xsl:template>
But the answer is always the same..(e1d1).. Because i call the function four times.. the answer is also four time. (e1d1e1d1e1d1e1d1)
I want to have a different character every time. A little bit like password generator but just with letters and numbers.
Tnx :)
In XSLT 3.0 (XPath 3.1) one can use the random-number-generator() function.
For XSLT 2.0 I would recommend using the random number functions of FXSL - see for example: "Casting the Dice with FXSL: Random Number Generation Functions in XSLT"
Using this, here is an implementation of the wanted random-string generation function:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:my="my">
<xsl:import href="C:/CVS-DDN/fxsl-xslt2/f/random.xsl"/>
<xsl:output method="text"/>
<xsl:variable name="vSeed" select=
"xs:integer(seconds-from-time(current-time()))
* xs:integer(minutes-from-time(current-time()))
* xs:integer(hours-from-time(current-time()))"/>
<xsl:template match="/">
<xsl:value-of select="my:randomStrings(25, 10, $vSeed)" separator="
"/>
</xsl:template>
<xsl:function name="my:randomStrings">
<xsl:param name="pRandomLength" as="xs:integer"/>
<xsl:param name="pNumResults" as="xs:integer" />
<xsl:param name="pSeed" as="xs:integer"/>
<xsl:variable name="vAlphaNum" select="'abcdefghijklmnopqrstuvwxyz0123456789'"/>
<xsl:variable name="vNums">
<xsl:call-template name="randomSequence">
<xsl:with-param name="pSeed" select="$pSeed"/>
<xsl:with-param name="pStart" select="1"/>
<xsl:with-param name="pEnd" select="36"/>
<xsl:with-param name="pLength" select="$pRandomLength*$pNumResults"/>
</xsl:call-template>
</xsl:variable>
<xsl:sequence select=
"for $vK in 1 to $pNumResults
return
string-join(for $i in
$vNums/*[position() gt ($vK -1)*$pRandomLength
and position() le $vK*$pRandomLength]
/xs:integer(.)
return substring($vAlphaNum, $i, 1),
'')
"/>
</xsl:function>
</xsl:stylesheet>
The function my:randomStrings(pRandomLength, pNumResults, pSeed) implemented above produces a sequence of random strings and has these three arguments:
pRandomLength - the wanted length of each generated random string
pNumResults - the wanted number of random strings to be generated
pSeed - a seed for the random generator. Calling the function with different seeds will produce different results.
The code above calls the function to produce 10 random strings each with length 25. The seed is calculated from the current time and thus the result will be different each time the transformation is performed.
Here is one result:
azdkex5yi5rm3suewa7bxazpc
qi2qsg7qvl7en4cx2c5s9vfrp
l8t0lv659uba500t6e7fea518
7bt80g6bpjtjltna7ru6e3t15
t90s62fvnex5yqcq2osv97n5z
hibzw8g95wv15x2s2wv8cobem
dqiubm165tp1pci34hparuqs7
5d0chkl85liaowx3v88isk4oo
6iw5iktzaqa7jnf4g9lakqdhk
insg7iggsc22fqd1jkhbrxo53
And here is another:
bstudsgn85xq7dncy9fubu8we
g9hkl0qf493u0x7xmaz0hunqd
9lyclhrp19iz33v0hdmt7txoh
b45t1t1xfves5fjn3syzilhjq
p5bh89iojemh7adb41suew20d
goznie54278vfb4968zx3n9o8
lmouaz8j7i033mtjx1t6ymbjn
jxgqajz7g9db0g6j4o8l6ukgw
2ge6nhv69emcqanc6f63yeoro
yws75ttmbnsbyxvwwch86wbe2
Note:
As noted, you need to have downloaded the FXSL library and you will need to set the href attribute of the <xsl:import> declaration above, to point to the exact location of the file system, where the imported stylesheet file resides.
const characters = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const charactersLength = characters.length;
const generate25letterrandomstring = () => {
let randomString = '';
for (let i = 0; i < 25; i++) {
randomString += characters.charAt(Math.floor(Math.random() * charactersLength));
}
console.log(randomString);
return randomString;
}
generate25letterrandomstring()

Remove Characters from XML Output in Postman

I'm making an XML API call in Postman and I get the following response:
<response>
<result>
<system>YYY:XXXXXXXXX</system>
</result>
</response>
I created a variable from the content in "system", but I need to remove the "YYY:" from the front. Here is how I created the variable:
var response = xml2Json(responseBody);
var uuid = response["response"]["result"]["system"];
pm.collectionVariables.set("uuid", uuid);
If that could be formatted to remove any possible other characters before the colon - ex: "CCC:" or "ABC:" or "VAR1:" - that would be a bonus, but hard-coding this to remove exactly "YYY:" would solve the current problem.
You could do this, split String by character ":"
let text = "YYY:XXXXXXXXX";
console.log(text.split(":")[1]);
Apply to your code:
var response = xml2Json(responseBody);
var uuid = response["response"]["result"]["system"];
pm.collectionVariables.set("uuid", uuid.split(":")[1]);
Result:

Getting PDFBox IO Exception: COSStream has been closed and cannot be read, while using PDF as background image in Apache FOP

I am generating a pdf file using Apache FOP - 2.5.x and I need to use some existing pdf as background images. I am using fop-pdf-images-2.3 to enable this. Fop-pdf-images uses PDFBox 2.0.20 to enable FOP to read pdf file as background image.
But I am sometimes getting this error
Error on PDF page: https://s2.q4cdn.com/498544986/files/doc_downloads/test.pdf COSStream has been closed and cannot be read. Perhaps its enclosing PDDocument has been closed?
at org.apache.fop.render.pdf.pdfbox.PDFBoxImageHandler.handleImage(PDFBoxImageHandler.java:84)
at org.apache.fop.render.intermediate.AbstractIFPainter.drawImage(AbstractIFPainter.java:249)
at org.apache.fop.render.intermediate.AbstractIFPainter.drawImage(AbstractIFPainter.java:205)
at org.apache.fop.render.intermediate.AbstractIFPainter.drawImageUsingImageHandler(AbstractIFPainter.java:170)
at org.apache.fop.render.pdf.PDFPainter.drawImageUsingURI(PDFPainter.java:218)
at org.apache.fop.render.pdf.PDFPainter.drawImage(PDFPainter.java:181)
at org.apache.fop.render.intermediate.IFRenderer.drawImage(IFRenderer.java:1301)
at org.apache.fop.render.AbstractPathOrientedRenderer.drawImage(AbstractPathOrientedRenderer.java:973)
at org.apache.fop.render.AbstractPathOrientedRenderer.drawBackground(AbstractPathOrientedRenderer.java:308)
at org.apache.fop.render.intermediate.IFRenderer.drawBackground(IFRenderer.java:1390)
at org.apache.fop.render.AbstractPathOrientedRenderer.drawBackground(AbstractPathOrientedRenderer.java:215)
at org.apache.fop.render.AbstractPathOrientedRenderer.drawBackAndBorders(AbstractPathOrientedRenderer.java:173)
at org.apache.fop.render.AbstractPathOrientedRenderer.handleRegionTraits(AbstractPathOrientedRenderer.java:128)
at org.apache.fop.render.AbstractRenderer.renderRegionViewport(AbstractRenderer.java:373)
at org.apache.fop.render.intermediate.IFRenderer.renderRegionViewport(IFRenderer.java:738)
at org.apache.fop.render.AbstractRenderer.renderPageAreas(AbstractRenderer.java:345)
at org.apache.fop.render.AbstractRenderer.renderPage(AbstractRenderer.java:318)
at org.apache.fop.render.intermediate.IFRenderer.renderPage(IFRenderer.java:587)
at org.apache.fop.area.RenderPagesModel.addPage(RenderPagesModel.java:123)
at org.apache.fop.layoutmgr.AbstractPageSequenceLayoutManager.finishPage(AbstractPageSequenceLayoutManager.java:316)
at org.apache.fop.layoutmgr.PageSequenceLayoutManager.finishPage(PageSequenceLayoutManager.java:243)
at org.apache.fop.layoutmgr.PageSequenceLayoutManager.activateLayout(PageSequenceLayoutManager.java:147)
at org.apache.fop.area.AreaTreeHandler.endPageSequence(AreaTreeHandler.java:267)
at org.apache.fop.fo.pagination.PageSequence.endOfNode(PageSequence.java:139)
at org.apache.fop.fo.FOTreeBuilder$MainFOHandler.endElement(FOTreeBuilder.java:362)
at org.apache.fop.fo.FOTreeBuilder.endElement(FOTreeBuilder.java:190)
at java.xml/com.sun.org.apache.xml.internal.serializer.ToXMLSAXHandler.endElement(ToXMLSAXHandler.java:263)
at java.xml/com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(AbstractSAXParser.java:610)
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(XMLDocumentFragmentScannerImpl.java:1718)
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2883)
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:605)
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:112)
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:534)
at java.xml/com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:888)
at java.xml/com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:824)
at java.xml/com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
at java.xml/com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1216)
at java.xml/com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:635)
at java.xml/com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transformIdentity(TransformerImpl.java:660)
at java.xml/com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:774)
... 7 more
Caused by: java.io.IOException: COSStream has been closed and cannot be read. Perhaps its enclosing PDDocument has been closed?
at org.apache.pdfbox.cos.COSStream.checkClosed(COSStream.java:154)
at org.apache.pdfbox.cos.COSStream.createInputStream(COSStream.java:239)
at org.apache.pdfbox.cos.COSStream.createInputStream(COSStream.java:234)
at org.apache.pdfbox.pdmodel.PDPage.getContents(PDPage.java:157)
at org.apache.fop.render.pdf.pdfbox.PDFBoxAdapter.getContents(PDFBoxAdapter.java:460)
at org.apache.fop.render.pdf.pdfbox.PDFBoxAdapter.createStreamFromPDFBoxPage(PDFBoxAdapter.java:352)
at org.apache.fop.render.pdf.pdfbox.AbstractPDFBoxHandler.createStreamForPDF(AbstractPDFBoxHandler.java:111)
at org.apache.fop.render.pdf.pdfbox.PDFBoxImageHandler.handleImage(PDFBoxImageHandler.java:71)
... 46 more
This error depends on the pageHeight and pageWidth in setup in my .fo file.
Here is my .fo file for the same.
{% set cardWidth = 8.3 %}
{% set cardHeight = 8 %}
{% set bleedLength = 0.125 %}
{% set totalWidth = cardWidth + 2 * bleedLength %}
{% set totalHeight = cardHeight + 2 * bleedLength %}
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="MyPick" page-width="{{ totalWidth }}in" page-height="{{ totalHeight }}in">
<fo:region-body background-image="https://s2.q4cdn.com/498544986/files/doc_downloads/test.pdf"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="MyPick">
<fo:flow flow-name="xsl-region-body">
<fo:block-container absolute-position="absolute" top="{{ bleedLength }}in" left="{{ bleedLength }}in" width="{{ cardWidth }}in"
height="{{ cardHeight }}in">
<fo:block-container display-align="center" margin-left="1.5in" margin-top="1.2in" margin-right="1.5in"
height="6.539in">
<fo:block-container margin="0">
<fo:block font-family="Bookerly Display" text-align="start" color="rgb(255,255,255)" font-size="160pt" line-height="1">
Header
</fo:block>
<fo:block font-family="Bookerly Display" margin-top="0.3in" text-align="start" color="rgb(255,255,255)" font-size="110pt" line-height="1">
SubHeader
</fo:block>
</fo:block-container>
</fo:block-container>
<fo:block margin-top="0.75in" margin-bottom="0.4175in" margin-right="0.39in" text-align="right" font-family="Arial" font-size="6pt"
color="rgb(255,255,255)">
Footer
</fo:block>
</fo:block-container>
</fo:flow>
</fo:page-sequence>
</fo:root>
If I change my page cardWidth from 8.3 to 8.2, the same pdf renders properly. I don't understand why the issue happens for some dimensions but for some dimensions FOP is able to generate the file without any issues.
I am using this sample pdf file to test : https://s2.q4cdn.com/498544986/files/doc_downloads/test.pdf

The ':' character, hexadecimal value 0x3A, cannot be included in a name

I saw this question already, but I didnt see an answer..
So I get this error:
The ':' character, hexadecimal value 0x3A, cannot be included in a name.
On this code:
XDocument XMLFeed = XDocument.Load("http://feeds.foxnews.com/foxnews/most-popular?format=xml");
XNamespace content = "http://purl.org/rss/1.0/modules/content/";
var feeds = from feed in XMLFeed.Descendants("item")
select new
{
Title = feed.Element("title").Value,
Link = feed.Element("link").Value,
pubDate = feed.Element("pubDate").Value,
Description = feed.Element("description").Value,
MediaContent = feed.Element(content + "encoded")
};
foreach (var f in feeds.Reverse())
{
....
}
An item looks like that:
<rss>
<channel>
....items....
<item>
<title>Pentagon confirms plan to create new spy agency</title>
<link>http://feeds.foxnews.com/~r/foxnews/most-popular/~3/lVUZwCdjVsc/</link>
<category>politics</category>
<dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/" />
<pubDate>Tue, 24 Apr 2012 12:44:51 PDT</pubDate>
<guid isPermaLink="false">http://www.foxnews.com/politics/2012/04/24/pentagon-confirms-plan-to-create-new-spy-agency/</guid>
<content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[|http://global.fncstatic.com/static/managed/img/Politics/panetta_hearing_030712.jpg<img src="http://feeds.feedburner.com/~r/foxnews/most-popular/~4/lVUZwCdjVsc" height="1" width="1"/>]]></content:encoded>
<description>The Pentagon confirmed Tuesday that it is carving out a brand new spy agency expected to include several hundred officers focused on intelligence gathering around the world.&amp;#160;</description>
<dc:date xmlns:dc="http://purl.org/dc/elements/1.1/">2012-04-4T19:44:51Z</dc:date>
<feedburner:origLink>http://www.foxnews.com/politics/2012/04/24/pentagon-confirms-plan-to-create-new-spy-agency/</feedburner:origLink>
</item>
....items....
</channel>
</rss>
All I want is to get the "http://global.fncstatic.com/static/managed/img/Politics/panetta_hearing_030712.jpg", and before that check if content:encoded exists..
Thanks.
EDIT:
I've found a sample that I can show and edit the code that tries to handle it..
EDIT2:
I've done it in the ugly way:
text.Replace("content:encoded", "contentt").Replace("xmlns:content=\"http://purl.org/rss/1.0/modules/content/\"","");
and then get the element in the normal way:
MediaContent = feed.Element("contentt").Value
The following code
static void Main(string[] args)
{
var XMLFeed = XDocument.Parse(
#"<rss>
<channel>
....items....
<item>
<title>Pentagon confirms plan to create new spy agency</title>
<link>http://feeds.foxnews.com/~r/foxnews/most-popular/~3/lVUZwCdjVsc/</link>
<category>politics</category>
<dc:creator xmlns:dc='http://purl.org/dc/elements/1.1/' />
<pubDate>Tue, 24 Apr 2012 12:44:51 PDT</pubDate>
<guid isPermaLink='false'>http://www.foxnews.com/politics/2012/04/24/pentagon-confirms-plan-to-create-new-spy-agency/</guid>
<content:encoded xmlns:content='http://purl.org/rss/1.0/modules/content/'><![CDATA[|http://global.fncstatic.com/static/managed/img/Politics/panetta_hearing_030712.jpg<img src='http://feeds.feedburner.com/~r/foxnews/most-popular/~4/lVUZwCdjVsc' height='1' width='1'/>]]></content:encoded>
<description>The Pentagon confirmed Tuesday that it is carving out a brand new spy agency expected to include several hundred officers focused on intelligence gathering around the world.&amp;#160;</description>
<dc:date xmlns:dc='http://purl.org/dc/elements/1.1/'>2012-04-4T19:44:51Z</dc:date>
<!-- <feedburner:origLink>http://www.foxnews.com/politics/2012/04/24/pentagon-confirms-plan-to-create-new-spy-agency/</feedburner:origLink> -->
</item>
....items....
</channel>
</rss>");
XNamespace contentNs = "http://purl.org/rss/1.0/modules/content/";
var feeds = from feed in XMLFeed.Descendants("item")
select new
{
Title = (string)feed.Element("title"),
Link = (string)feed.Element("link"),
pubDate = (string)feed.Element("pubDate"),
Description = (string)feed.Element("description"),
MediaContent = GetMediaContent((string)feed.Element(contentNs + "encoded"))
};
foreach(var item in feeds)
{
Console.WriteLine(item);
}
}
private static string GetMediaContent(string content)
{
int imgStartPos = content.IndexOf("<img");
if(imgStartPos > 0)
{
int startPos = content[0] == '|' ? 1 : 0;
return content.Substring(startPos, imgStartPos - startPos);
}
return string.Empty;
}
results in:
{ Title = Pentagon confirms plan to create new spy agency, Link = http://feeds.f
oxnews.com/~r/foxnews/most-popular/~3/lVUZwCdjVsc/, pubDate = Tue, 24 Apr 2012 1
2:44:51 PDT, Description = The Pentagon confirmed Tuesday that it is carving out
a brand new spy agency expected to include several hundred officers focused on
intelligence gathering around the world. , MediaContent = http://global
.fncstatic.com/static/managed/img/Politics/panetta_hearing_030712.jpg }
Press any key to continue . . .
A few points:
You never want to treat Xml as text - in your case you removed the namespace declaration but actually if the namespace was declared inline (i.e. without binding to the prefix) or a different prefix would be defined your code would not work even though semantically both documents would be equivalent
Unless you know what's inside CDATA and how to treat it you always want to treat is as text. If you know it's something else you can treat it differently after parsing - see my elaborate on CDATA below for more details
To avoid NullReferenceExceptions if the element is missing I used explicit conversion operator (string) instead of invoking .Value
the Xml you posted was not a valid xml - there was missing namespace Uri for feedburner prefix
This is no longer related to the problem but may be helpful for some folks so I am leaving it
As far as the contents of the encode element is considered it is inside CDATA section. What's inside CDATA section is not an Xml but plain text. CDATA is usually used to not have to encode '<', '>', '&' characters (without CDATA they would have to be encoded as < > and & to not break the Xml document itself) but the Xml processor treat characters in the CDATA as if they were encoded (or to be more correct in encodes them). The CDATA is convenient if you want to embed html because textually the embedded content looks like the original yet it won't break your xml if the html is not a well-formed Xml. Since the CDATA content is not an Xml but text it is not possible to treat it as Xml. You will probably need to treat is as text and use for instance regular expressions. If you know it is a valid Xml you can load the contents to an XElement again and process it. In your case you have got mixed content so it is not easy to do unless you use a little dirty hack. Everything would be easy if you have just one top level element instead of mixed content. The hack is to add the element to avoid all the hassle. Inside the foreach look you can do something like this:
var mediaContentXml = XElement.Parse("<content>" + (string)item.MediaContent + "</content>");
Console.WriteLine((string)mediaContentXml.Element("img").Attribute("src"));
Again it's not pretty and it is a hack but it will work if the content of the encoded element is valid Xml. The more correct way of doing this is to us XmlReader with ConformanceLevel set to Fragment and recognize all kinds of nodes appropriately to create a corresponding Linq to Xml node.
You should use XNamespace:
XNamespace content = "...";
// later in your code ...
MediaContent = feed.Element(content + "encoded")
See more details here.
(Of course, you the string to be assigned to content is the same as in xmlns:content="...").

WCF DataContractSerializer Behavior

I'm seeing some unusual behavior when using the DataContractSerializer. I have defined a message contract like so:
namespace MyNamespace.DataContracts
{
[MessageContract(WrapperName = "order", WrapperNamespace = #"http://example.com/v1/order")]
public class MyOrder
{
[MessageBodyMember(Namespace = #"http://example.com/v1/order", Order = 1)]
public MyStore store;
[MessageBodyMember(Namespace = #"http://example.com/v1/order", Order = 2)]
public MyOrderHeader orderHeader;
[MessageBodyMember(Namespace = #"http://example.com/v1/order", Order = 3)]
public List<MyPayment> payments;
[MessageBodyMember(Namespace = #"http://example.com/v1/order", Order = 4)]
public List<MyShipment> shipments;
}
.
.
I'm sending it an XML message that looks like this:
<?xml version="1.0" encoding="utf-8"?>
<order xmlns="http://example.com/v1/order>
<store>
...
</store>
<orderHeader>
...
</orderHeader>
<payments>
<payment>
...
</payment>
</payments>
<shipments>
<shipment>
...
</shipment>
</shipments>
</order>
My service deserializes this XML as expected. Inside my service, I'm using the DataContractSerializer to create an XML string and that's where things get weird. I'm using the serializer like this:
DataContractSerializer serializer = new DataContractSerializer(typeof(MyOrder));
using (MemoryStream ms = new MemoryStream())
{
serializer.WriteObject(ms, order);
ms.Position = 0;
StreamReader sr = new StreamReader(ms);
string outputMessage = sr.ReadToEnd();
}
Once this finishes, the outputMessage contains the following XML:
<?xml version="1.0" encoding="utf-8"?>
<MyOrder xmlns="http://example.com/v1/order" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<order>
<store>
...
</store>
<orderHeader>
...
</orderHeader>
<payments>
<payment>
...
</payment>
</payments>
<shipments>
<shipment>
...
</shipment>
</shipments>
</order>
</MyOrder>
Needless to say, anything expecting to receive the original XML message will fail to parse this. So I guess I have two questions:
Why is the DataContractSerializer
adding the extra outer node to my
XML output?
Is there a way to stop it from doing
this?
Thanks.
I should probably add this is with .NET 4.
You could try using WriteObjectContent instead of WriteObject, but I'm unable to reproduce your problem using the code you supplied. All the extra class defintions that are part of your message contract are empty in my definition, but this is the XML I am getting:
<MyOrder xmlns="http://schemas.datacontract.org/2004/07/SandboxApp"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<orderHeader i:nil="true"/>
<payments i:nil="true"/>
<shipments i:nil="true"/>
<store i:nil="true"/>
</MyOrder>
Which also seems odd, since it seems to ignore the WrapperName. Same result in .NET 3.5 SP1 and .NET 4.0.